數據的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)