golang json編碼

數據的json編碼主要涉及兩個方法調用:

1.Marshal方法

該方法返回參數v的json編碼

func Marshal(v interface{}) ([]byte, error) {
    e := newEncodeState()

    err := e.marshal(v, encOpts{escapeHTML: true})
    if err != nil {
        return nil, err
    }
    buf := append([]byte(nil), e.Bytes()...)

    e.Reset()
    encodeStatePool.Put(e)

    return buf, nil
}

該方法可以接受任意類型的參數,并將其轉化為字節序列,如果遇到的值實現了Marshaler接口,并且不是一個空指針,Marshal方法就會調用其上的MarshalJSON方法來產生JSON對象。如果沒有MarshalJSON方法,但是它實現了encoding.TextMarshaler,Marshal調用marshalText方法,并將結果編碼為JSON字符串。否則,Marshal方法使用以下的依賴于類型的默認編碼;

  • boolean值編碼為JSON的boolean值
  • 浮點數,整型,Number類型的值編碼為JSON的number值
  • 字符串類型編碼為有效的UTF-8編碼的JSON字符串值,使用rune類型替換無效的字節,尖括號<、>變為"\u003c","\u003e",以防止某些瀏覽器將JSON輸出錯誤的解釋為HTML."&"變成"\u0026"也是同樣的原因。可以通過SetEscapeHTML(false)來禁止此轉義。
  • 數組和切片類型編碼為JSON數組,除了[]byte字節數組編碼為bash64的字符串。nil的切片會編碼為null的JSON值。
    var a []int = []int{1, 2, 3, 4, 6}
    sliceJSON, err := json.Marshal(a)
    fmt.Println(string(sliceJSON)) //[1,2,3,4,6]
  • 結構體編碼為JSON對象。每一個導出的結構體字段變成JSON對象的成員,使用字段名作為JSON對象的一個key.除非字段以以下的方式被省略了:
    每個字段的編碼可以通過結構體的字段標簽來定制。標簽可以給出字段的名稱,也可以為空, 來使用默認的字段名。omitempty可選項指定字符如果為空值,在編碼的時候,需要忽略,以下值可以定義為空值:false,0,nil指針,nil接口,空數組,空字符串,空字典,空切片。特別的,如果字段標簽為"-"",字段將在編時被忽略,如果標簽為"-,"",編碼后,出現在JSON對象中時,字段名將為-。
  • "string"字符串標簽標示字段將被編碼為JSON字符串,該標簽僅在字段類型為字符串,浮點數,整數,布爾類型時,使用。
  • 指針類型的值編碼為指針指向的值,空指針將被編碼為null值。
  • 接口類型的值將被編碼為接口中包含的值,空的接口值將被編碼為null值。
  • channel,complex,函數類型的值不能被編碼,試圖編碼將報錯。
  • 循環引用的數據Marshal將不處理它們,傳入一個循環結構的數據到Marshal中將導致一個無線循環。
package main

import (
    "encoding/json"
    "fmt"
    "reflect"
)

type User struct {
    Name  string `json:"user_name"`
    Age   int    `json:"user_age"`
    Addr  string `json:"address,omitempty"`
    Email string `json:",omitempty"`
    *IphoneInfo
}

type IphoneInfo struct {
    Id     int64       `json:"iphone_id"`
    Name   string      `json:"iphone_name"`
    IpAddr interface{} `json:"iphone_ip_addr"`
    IphoneType
}

type IphoneType struct {
    IphoneNumber string `json:"iphone_number"`
    Is5GIphone   bool   `json:"is_5g"`
}

func main() {
    var user User = User{
        Name: "yechongqiu",
        Age:  18,
        Addr: "Nanjiing",
        // Email: "yechongqiu@sunning.com",
    }
    fmt.Println(reflect.ValueOf(user) == reflect.ValueOf(&user))
    fmt.Println(reflect.ValueOf(&user))
    jsonUser, err := json.Marshal(&user)
    if err != nil {
        return
    }
    fmt.Println(string(jsonUser))
    var a []int = []int{1, 2, 3, 4, 6}
    sliceJSON, err := json.Marshal(a)
    fmt.Println(string(sliceJSON))

    iphoneInfo := &IphoneInfo{
        Id:     100001,
        Name:   "iphone 8",
        IpAddr: "192.168.10.101",
    }
    user.IphoneInfo = iphoneInfo
    jsonUser2, err := json.Marshal(user)
    if err != nil {
        return
    }
    fmt.Println(string(jsonUser2))
}

Output:

false
&{yechongqiu 18 Nanjiing  <nil>}
{"user_name":"yechongqiu","user_age":18,"address":"Nanjiing"}
[1,2,3,4,6]
{"user_name":"yechongqiu","user_age":18,"address":"Nanjiing","iphone_id":100001,"iphone_name":"iphone 8","iphone_ip_addr":"192.168.10.101","iphone_number":"","is_5g":false}

Unmarshal

將JSON對象解碼為結構體數據,方法的參數為:

  • 需要解碼的JSON對象的字節序列
  • 將JOSN對象解碼到的結構體,一般為指針。
func Unmarshal(data []byte, v interface{}) error {
    // Check for well-formedness.
    // Avoids filling out half a data structure
    // before discovering a JSON syntax error.
    var d decodeState
    err := checkValid(data, &d.scan)
    if err != nil {
        return err
    }

    d.init(data)
    return d.unmarshal(v)
}

如果第二個參數為空,或者不是一個指針,將返回一個錯誤。Unmarshal使用Marshal相反的編碼。使用以下附加規則:

為了解碼JSON到一個實現了Unmarshaler接口的值,Unmarshal方法調用值的UnmarshalJSON方法。包含輸入為JSON null的情況。否則,如果值實現了encoding.TextUnmarshaler接口,Unmarshal方法將調用值的該方法。
為了解碼一個JOSN到一個結構體,Unmarshal匹配輸入類型的key到Marshal時使用的key.

解碼JSON到一個接口值時,將如下的值保存到接口中去:

  • json boolean -> bool
  • json number -> float64
  • json string -> string
  • json arrays -> []interface{}
  • json objects -> map[string]interface{}
  • json null -> nil

為了將一個JSON數組解碼到一個切片中,Unmarshal將重置切片長度為0,然后再將每個元素追加到切片中。特別的,將一個空的JSON數組解碼到一個切片中,Unmarshal使用一個空的切片替換切片。

為了將一個JSON對象解碼到map中,Unmarshal 首先建立一個map,如果map為nil,將重新分配一個,否則直接使用它,保留之前的鍵值對,然后將JSON對象的key-value對存到map中去。map的鍵類型必須是一個字符串,或者整數,或者實現了excoding.TextUnmarshaler接口的類型。

如果一個JSON值不適合給的目標值的類型。或者JSON數字值范圍超過了目標類型的范圍,Unmarshal將跳過它,盡可能的完成其他解碼。如果沒有遇到更加嚴重的錯誤,Unmarshal將返回一個描述早前錯誤的異常。

    err = json.Unmarshal(jsonUser2, &userFromJSON)
    if err != nil {
        return
    }
    fmt.Println(userFromJSON)
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容