最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Golang實(shí)現(xiàn)Json分級(jí)解析及數(shù)字解析實(shí)踐詳解

 更新時(shí)間:2023年02月14日 15:25:30   作者:小嘴叭叭兒  
你是否遇到過(guò)在無(wú)法準(zhǔn)確確定json層級(jí)關(guān)系的情況下對(duì)json進(jìn)行解析的需求呢?本文就來(lái)和大家介紹一次解析不確定的json對(duì)象的經(jīng)歷,以及遇到的問(wèn)題和解決方法

一、背景介紹

在go語(yǔ)言開(kāi)發(fā)過(guò)程中經(jīng)常需要將json字符串解析為struct,通常我們都是根據(jù)json的具體層級(jí)關(guān)系定義對(duì)應(yīng)的struct,然后通過(guò)json.Unmarshal()命令實(shí)現(xiàn)json到struct對(duì)象的轉(zhuǎn)換,然后再根據(jù)具體邏輯處理相應(yīng)的數(shù)據(jù)。

你是否遇到過(guò)在無(wú)法準(zhǔn)確確定json層級(jí)關(guān)系的情況下對(duì)json進(jìn)行解析的需求呢?

接下來(lái)我將介紹一次解析不確定的json對(duì)象的經(jīng)歷,以及遇到的問(wèn)題和解決方法。

假設(shè)我們需要調(diào)用某個(gè)http接口從而獲得一件商品的相似品推薦結(jié)果,該服務(wù)的輸入?yún)?shù)只有一個(gè)skuId參數(shù),接口的返回?cái)?shù)據(jù)時(shí)json格式,并且同時(shí)存在兩種返回參數(shù)。我們無(wú)法通過(guò)入?yún)⑴袛嘟涌诜祷啬囊环N結(jié)果(估計(jì)這種異常是http服務(wù)開(kāi)發(fā)者無(wú)意導(dǎo)致的,但是沒(méi)辦法,我們必須基于該服務(wù)接口開(kāi)發(fā)某種功能。)

具體的,返回結(jié)果有兩種情況

第一種

{
  "return": "0",
  "result":[
    {
      "goods_id": 37278077211,
      ....
      "shop_name": "xxxxx",
    },
    {
      "goods_id": 236492067349,
      ....
      "shop_name": "xxxxx",
    }
    ]
}

第二種

{
  "return": "0",
  "result": {
    "data": [
      {
        "goods_id": 58054798450,
        ......
        "shop_name": "xxxxxxxx"
      },
      {
        "goods_id": 27395404673,
        ......
        "shop_name": "xxxxxxxx"
      }
    ]
  }
}

二、解決方案

(1)將Json直接解析為map

由于在解析前我們并不能確定result到底是一個(gè)struct還是一個(gè)Slice,因此我們也無(wú)法直接利用json.Unmarshal一步解出對(duì)應(yīng)的struct對(duì)象。好在我們知道所有json都可以直接解析成map[string]interface{}的結(jié)構(gòu),因此我們可以將json先轉(zhuǎn)化為map,然后根據(jù)結(jié)構(gòu)名key去決定后續(xù)的轉(zhuǎn)換流程,具體代碼如下:

var object interface{}
var data interface{}

err := json.Unmarshal([]byte(jsonStr),&object)
if err != nil{
    fmt.Printf("unmarshal %s error: %s\n",jsonStr,err.Error())
}

//判斷returnCode
ret := object.(map[string]interface{})["return"]
if ret != 0{
    fmt.Println("the response of http error")
}

//判斷result是何種類(lèi)型
result := object.(map[string]interface{})["result"]
resultType := reflect.TypeOf(result)

if resultType.Kind() == reflect.Map{
    data = result.(map[string]interface{})["data"]
}

if resultType.Kind() == reflect.Slice{
    data = result
}

//解析goods_id
var skuList []int64
for _,v :=  range data.([]interface{}){
    preSku := v.(map[string]interface{})["goods_id"].(float64)
    skuList = append(skuList,int64(preSku))
}

fmt.Printf("the skuLst = %+v\n",skuList)

這種方式的優(yōu)點(diǎn)是只需要Unmarshal一次,缺點(diǎn)是每一級(jí)都需要顯示的去做類(lèi)型轉(zhuǎn)化,書(shū)寫(xiě)起來(lái)比較繁瑣。尤其是json本身結(jié)構(gòu)復(fù)雜,其中只有一小部分需要確定具體類(lèi)型的情況下,解析過(guò)程會(huì)更加繁瑣復(fù)雜。

那么是否可以只解析確定部分,不確定的部分先保留[]byte的原始格式,按map解析呢?

答案是肯定的。這時(shí)候就需要用到j(luò)son.RawMessage字段類(lèi)型了

(2)解析部分json struct的方法 (json.RawMessage的用法)

在解析json過(guò)程中,有時(shí)我們可能只需要解析json的某一部分?jǐn)?shù)據(jù),比如,當(dāng)json中只有一部分是我們需要的數(shù)據(jù),或者我們需要先解析一部分?jǐn)?shù)據(jù),才能根據(jù)解析的部分?jǐn)?shù)據(jù)來(lái)決定剩余數(shù)據(jù)如何解析。我們繼續(xù)以上面的需求為例。此時(shí)需要我們預(yù)先定義需要解析的部分

type RespStruct struct {
    RetCode int `json:"return"`
    Result json.RawMessage `json:"result"`
}

我們首先解析return字段。result字段內(nèi)容將繼續(xù)保持[]byte類(lèi)型的狀態(tài)。接下來(lái)我們繼續(xù)解析剩余部分

var object RespStruct

err := json.Unmarshal([]byte(jsonStr2),&object)
if err != nil{
    fmt.Printf("unmarshal %s error: %s\n",jsonStr,err.Error())
}

//判斷returnCode
if object.RetCode != 0{
    fmt.Println("the response of http error")
}

//判斷result是何種類(lèi)型
var data interface{}

err = json.Unmarshal(object.Result,&data)
if err != nil{
    fmt.Printf("unmarshal %s error: %s\n",object.Result,err.Error())
}

resultType := reflect.TypeOf(data)

if resultType.Kind() == reflect.Map{
    data = data.(map[string]interface{})["data"]
}


//解析goods_id
var skuList []int64
for _,v :=  range data.([]interface{}){
    preSku := v.(map[string]interface{})["goods_id"].(float64)
    skuList = append(skuList,int64(preSku))
}

fmt.Printf("the skuLst = %+v\n",skuList)

看到這里,有人可能會(huì)產(chǎn)生疑問(wèn),我可不可以將不需要解析的字段定義為[]byte 類(lèi)型呢,畢竟解析為rawMessage類(lèi)型后,該字段本身也是[]byte。通過(guò)實(shí)驗(yàn)我們發(fā)現(xiàn)是不可以的,如果將rawMessage替換為 []byte類(lèi)型,解析過(guò)程會(huì)返回錯(cuò)誤,因?yàn)樵趈son包中,雖然RawMessage類(lèi)型時(shí) []byte的別名,但是解析過(guò)程中,只處理rawMessage類(lèi)型(golang 是強(qiáng)類(lèi)型編程語(yǔ)言)。

type RawMessage []byte

(3) json.Number類(lèi)型的使用

在上個(gè)實(shí)驗(yàn)中,有些同學(xué)可能發(fā)現(xiàn),為什么goods_id字段的類(lèi)型先由interface{}類(lèi)型轉(zhuǎn)為float64,然后才被轉(zhuǎn)換為我們需要的int64呢?

這是因?yàn)樵?json 中是沒(méi)有整型和浮點(diǎn)型之分的,當(dāng)我們利用json 包中的 Unmarshal 方法將數(shù)字類(lèi)型解析為interface{}時(shí),它就會(huì)將把所有數(shù)字類(lèi)型全部轉(zhuǎn)換為和規(guī)范最接近的float64類(lèi)型。如果我們希望更加方便的將數(shù)字類(lèi)型準(zhǔn)換為指定的類(lèi)型,就需要用到j(luò)son.Number這個(gè)類(lèi)型。具體如下:

var object RespStruct

err := json.Unmarshal([]byte(jsonStr),&object)
if err != nil{
    fmt.Printf("unmarshal %s error: %s\n",jsonStr,err.Error())
}

//判斷returnCode
if object.RetCode != 0{
    fmt.Println("the response of http error")
}

//判斷result是何種類(lèi)型
var data interface{}

decoder := json.NewDecoder(bytes.NewReader(object.Result))
decoder.UseNumber()
decoder.Decode(&data)

resultType := reflect.TypeOf(data)

if resultType.Kind() == reflect.Map{
    data = data.(map[string]interface{})["data"]
}


//解析goods_id
var skuList []int64
for _,v :=  range data.([]interface{}){
    preSku,err := v.(map[string]interface{})["goods_id"].(json.Number).Int64()
    if err != nil{
        fmt.Printf("get goods_id error")
    }
    skuList = append(skuList,preSku)
}

fmt.Printf("the skuLst = %+v\n",skuList)

利用json.Number類(lèi)型可以讓我們很方便的將數(shù)字類(lèi)型轉(zhuǎn)換成我們想要的類(lèi)型,除了轉(zhuǎn)換為int64類(lèi)型外,還支持轉(zhuǎn)換為float64和string。

為了進(jìn)一步了解json.Number的實(shí)現(xiàn),我們查看相關(guān)源碼可以發(fā)現(xiàn)

//decode.go

// A Number represents a JSON number literal.
type Number string

// String returns the literal text of the number.
func (n Number) String() string { return string(n) }

// Float64 returns the number as a float64.
func (n Number) Float64() (float64, error) {
    return strconv.ParseFloat(string(n), 64)
}

// Int64 returns the number as an int64.
func (n Number) Int64() (int64, error) {
    return strconv.ParseInt(string(n), 10, 64)
}

通過(guò)源碼我們可以發(fā)現(xiàn)json.Number本身是string類(lèi)型,只是在json包中被定義了別名,然后通過(guò)封裝的三個(gè)方法,實(shí)現(xiàn)了將string轉(zhuǎn)換為int64和float64類(lèi)型的方法。

以上就是Golang實(shí)現(xiàn)Json分級(jí)解析及數(shù)字解析實(shí)踐詳解的詳細(xì)內(nèi)容,更多關(guān)于Golang Json分級(jí)解析的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • go語(yǔ)言如何導(dǎo)入和使用包示例詳解

    go語(yǔ)言如何導(dǎo)入和使用包示例詳解

    這篇文章主要為大家介紹了go語(yǔ)言如何導(dǎo)入和使用包示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-08-08
  • 一文初探Go語(yǔ)言中的reflect反射包

    一文初探Go語(yǔ)言中的reflect反射包

    這篇文章主要和大家分享一下Go語(yǔ)言中的reflect反射包,文中的示例代碼講解詳細(xì),對(duì)我們學(xué)習(xí)Go語(yǔ)言有一定的幫助,需要的小伙伴可以參考一下
    2022-12-12
  • Go語(yǔ)言的常量、枚舉、作用域示例詳解

    Go語(yǔ)言的常量、枚舉、作用域示例詳解

    這篇文章主要介紹了Go語(yǔ)言的常量、枚舉、作用域,接下來(lái),我們將詳細(xì)了解 Go 的變量作用域規(guī)則以及這些規(guī)則如何影響代碼編寫(xiě),需要的朋友可以參考下
    2024-07-07
  • Go語(yǔ)言zip文件的讀寫(xiě)操作

    Go語(yǔ)言zip文件的讀寫(xiě)操作

    本文主要介紹了Go語(yǔ)言zip文件的讀寫(xiě)操作,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2023-04-04
  • go語(yǔ)言VScode?see?'go?help?modules'?(exit?status?1)問(wèn)題的解決過(guò)程

    go語(yǔ)言VScode?see?'go?help?modules'?(exit?statu

    最近上手學(xué)習(xí)go語(yǔ)言,準(zhǔn)備在VSCode上寫(xiě)程序的時(shí)候卻發(fā)現(xiàn)出了一點(diǎn)問(wèn)題,下面這篇文章主要給大家介紹了關(guān)于go語(yǔ)言VScode?see?'go?help?modules'(exit?status?1)問(wèn)題的解決過(guò)程,需要的朋友可以參考下
    2022-07-07
  • golang?channel管道使用示例解析

    golang?channel管道使用示例解析

    這篇文章主要介紹了golang?channel管道使用示例解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步早日升職加薪
    2022-04-04
  • linux下通過(guò)go語(yǔ)言獲得系統(tǒng)進(jìn)程cpu使用情況的方法

    linux下通過(guò)go語(yǔ)言獲得系統(tǒng)進(jìn)程cpu使用情況的方法

    這篇文章主要介紹了linux下通過(guò)go語(yǔ)言獲得系統(tǒng)進(jìn)程cpu使用情況的方法,實(shí)例分析了Go語(yǔ)言使用linux的系統(tǒng)命令ps來(lái)分析cpu使用情況的技巧,需要的朋友可以參考下
    2015-03-03
  • Go1.18新特性之泛型使用三步曲(小結(jié))

    Go1.18新特性之泛型使用三步曲(小結(jié))

    本文主要介紹了Go1.18新特性之泛型,是Go1.18的新特性,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2022-04-04
  • Go語(yǔ)言Cookie用法分析

    Go語(yǔ)言Cookie用法分析

    這篇文章主要介紹了Go語(yǔ)言Cookie用法,結(jié)合實(shí)例形式分析了Go語(yǔ)言Cookie的設(shè)置、讀取等相關(guān)操作技巧,需要的朋友可以參考下
    2017-02-02
  • Go語(yǔ)言通過(guò)smtp發(fā)送郵件的方法

    Go語(yǔ)言通過(guò)smtp發(fā)送郵件的方法

    這篇文章主要介紹了Go語(yǔ)言通過(guò)smtp發(fā)送郵件的方法,涉及Go語(yǔ)言發(fā)送郵件的技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下
    2015-02-02

最新評(píng)論

湾仔区| 德庆县| 乌审旗| 阿拉善左旗| 揭东县| 府谷县| 文水县| 宁津县| 天峨县| 大竹县| 庆阳市| 集贤县| 襄汾县| 津南区| 宣城市| 南昌县| 池州市| 沿河| 秦皇岛市| 沙河市| 康保县| 甘德县| 吉木萨尔县| 平罗县| 盐源县| 华阴市| 府谷县| 潍坊市| 启东市| 三原县| 四会市| 望都县| 会泽县| 舞钢市| 阿合奇县| 郁南县| 太仆寺旗| 荔波县| 池州市| 辽源市| 信宜市|