欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

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

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

一、背景介紹

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

你是否遇到過在無法準確確定json層級關系的情況下對json進行解析的需求呢?

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

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

具體的,返回結果有兩種情況

第一種

{
  "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到底是一個struct還是一個Slice,因此我們也無法直接利用json.Unmarshal一步解出對應的struct對象。好在我們知道所有json都可以直接解析成map[string]interface{}的結構,因此我們可以將json先轉化為map,然后根據(jù)結構名key去決定后續(xù)的轉換流程,具體代碼如下:

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是何種類型
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)點是只需要Unmarshal一次,缺點是每一級都需要顯示的去做類型轉化,書寫起來比較繁瑣。尤其是json本身結構復雜,其中只有一小部分需要確定具體類型的情況下,解析過程會更加繁瑣復雜。

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

答案是肯定的。這時候就需要用到json.RawMessage字段類型了

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

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

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

我們首先解析return字段。result字段內(nèi)容將繼續(xù)保持[]byte類型的狀態(tà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是何種類型
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)

看到這里,有人可能會產(chǎn)生疑問,我可不可以將不需要解析的字段定義為[]byte 類型呢,畢竟解析為rawMessage類型后,該字段本身也是[]byte。通過實驗我們發(fā)現(xiàn)是不可以的,如果將rawMessage替換為 []byte類型,解析過程會返回錯誤,因為在json包中,雖然RawMessage類型時 []byte的別名,但是解析過程中,只處理rawMessage類型(golang 是強類型編程語言)。

type RawMessage []byte

(3) json.Number類型的使用

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

這是因為在 json 中是沒有整型和浮點型之分的,當我們利用json 包中的 Unmarshal 方法將數(shù)字類型解析為interface{}時,它就會將把所有數(shù)字類型全部轉換為和規(guī)范最接近的float64類型。如果我們希望更加方便的將數(shù)字類型準換為指定的類型,就需要用到json.Number這個類型。具體如下:

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是何種類型
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類型可以讓我們很方便的將數(shù)字類型轉換成我們想要的類型,除了轉換為int64類型外,還支持轉換為float64和string。

為了進一步了解json.Number的實現(xià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)
}

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

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

相關文章

  • Go中使用單調(diào)時鐘獲得準確的時間間隔問題

    Go中使用單調(diào)時鐘獲得準確的時間間隔問題

    這篇文章主要介紹了Go中使用單調(diào)時鐘獲得準確的時間間隔,在go語言中,沒有直接調(diào)用時鐘的函數(shù),可以通過?time.Now()?獲得帶單調(diào)時鐘的?Time?結構體,并通過Since和Until獲得相對準確的時間間隔,需要的朋友可以參考下
    2022-06-06
  • go中值傳遞和指針傳遞的使用

    go中值傳遞和指針傳遞的使用

    在Go語言中,使用&和*可以分別取得變量的地址和值,解引用未初始化或為nil的指針會引發(fā)空指針異常,正確的做法是先進行nil檢查,此外,nil在Go中用于多種類型的空值表示,值傳遞和指針傳遞各有適用場景,通常小型數(shù)據(jù)結構優(yōu)先考慮值傳遞以減少解引用開銷
    2024-10-10
  • golang中實現(xiàn)給gif、png、jpeg圖片添加文字水印

    golang中實現(xiàn)給gif、png、jpeg圖片添加文字水印

    這篇文章主要介紹了golang中實現(xiàn)給gif、png、jpeg圖片添加文字水印,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2021-04-04
  • golang字符串本質(zhì)與原理詳解

    golang字符串本質(zhì)與原理詳解

    這篇文章主要介紹了golang字符串本質(zhì)與原理詳解,golang中的字符串指的是所有8比特位字節(jié)字符串的集合,通常是UTF-8編碼的文本,更多相關內(nèi)容需要的小伙伴可以參考一下
    2022-06-06
  • go語言中讀取配置文件的方法總結

    go語言中讀取配置文件的方法總結

    這篇文章主要為大家詳細介紹了go語言中讀取配置文件的幾個常見方法,文中的示例代碼講解詳細,具有一定的借鑒價值,需要的小伙伴可以參考下
    2023-08-08
  • golang 結構體初始化時賦值格式介紹

    golang 結構體初始化時賦值格式介紹

    這篇文章主要介紹了golang 結構體初始化時賦值格式介紹,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2020-12-12
  • 如何在Golang中運行JavaScript

    如何在Golang中運行JavaScript

    最近寫一個程序,接口返回的數(shù)據(jù)是js格式的,需要通過golang來解析js,所以下面這篇文章主要給大家介紹了關于如何在Golang中運行JavaScript的相關資料,需要的朋友可以參考下
    2022-01-01
  • Go實現(xiàn)mongodb增刪改查工具類的代碼示例

    Go實現(xiàn)mongodb增刪改查工具類的代碼示例

    這篇文章主要給大家介紹了關于Go實現(xiàn)mongodb增刪改查工具類的相關資料,MongoDB是一個NoSQL數(shù)據(jù)庫,它提供了靈活的文檔存儲模型以及強大的查詢和操作功能,需要的朋友可以參考下
    2023-10-10
  • golang使用viper加載配置文件實現(xiàn)自動反序列化到結構

    golang使用viper加載配置文件實現(xiàn)自動反序列化到結構

    這篇文章主要為大家介紹了golang使用viper加載配置文件實現(xiàn)自動反序列化到結構示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-08-08
  • golang?http請求未釋放造成的錯誤問題

    golang?http請求未釋放造成的錯誤問題

    這篇文章主要介紹了golang?http請求未釋放造成的錯誤問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2024-01-01

最新評論