Golang的對象和JSON字符串相互轉(zhuǎn)化

Json(Javascript Object Nanotation)是一種數(shù)據(jù)交換格式,常用于前后端數(shù)據(jù)傳輸。任意一端將數(shù)據(jù)轉(zhuǎn)換成json字符串,另一端再將該字符串解析成相應(yīng)的數(shù)據(jù)結(jié)構(gòu),如string類型,strcut對象等。go語言本身為我們提供了json的工具包encoding/json

1 序列化為json字符串

1.1 Marshal

package main 
import ( 
    "encoding/json" 
    "fmt" 
    "os" 
) 
func main ( ) { 
    type ColorGroup struct { 
        ID     int 
        Name   string `json:"name"`
        Colors [ ] string 
    note   string
    } 
    group := ColorGroup { 
        ID :     1 , 
        Name :   "Reds" , 
        Colors : [ ] string { "Crimson" , "Red" , "Ruby" , "Maroon" } , 
    } 
    b , err := json. Marshal ( group ) 
    if err != nil { 
        fmt. Println ( "error:" , err ) 
    } 
    os. Stdout . Write ( b ) 
}

結(jié)果輸出:

{"ID":1,"name":"Reds","Colors":["Crimson","Red","Ruby","Maroon"]}

1.2 序列化備注

  1. 只有首字母是大寫的成員才可以序列化為JSON
    只有可導(dǎo)出成員(變量首字母大寫)才可以序列化為json。因成員變量note是不可導(dǎo)出的,故無法轉(zhuǎn)成json。
  2. 序列化為JSON的字段名稱可以指定
    如果變量打上了json標(biāo)簽,如Name旁邊的json:"name",那么轉(zhuǎn)化成的json key就用該標(biāo)簽name而不是Name
    否則取變量名作為key,如IDColors。
  3. 可以序列化為JSON的類型和限制
  • 基本數(shù)據(jù)類型和普通的結(jié)構(gòu)體都可以序列化,如bool類型也是可以直接轉(zhuǎn)換為json的value值。循環(huán)的數(shù)據(jù)結(jié)構(gòu)不能序列化為JSON,它會導(dǎo)致marshal陷入死循環(huán)。
  • channel,complex 以及函數(shù)不能被編碼json字符串。
  1. 指針變量編碼時自動轉(zhuǎn)換為它所指向的值
    指針變量編碼時自動轉(zhuǎn)換為它所指向的值,與直接定義為結(jié)構(gòu)體對象類型效果一樣,只不過指針更快,且能節(jié)省內(nèi)存空間。
  2. 對象序列化為json后就成為純粹的字符串。
  3. 包含通用類型的對象序列化
    成員變量都是已知的類型,只能接收指定的類型,比如string類型的Name只能賦值string類型的數(shù)據(jù)。
    有時為了通用性或使代碼簡潔,我們希望有一種類型可以接受各種類型的數(shù)據(jù),并序列化為json,就需要使用interface{}類型。無論是string,int,bool,還是指針類型等,都可賦值給interface{}類型,且正常編碼,效果與前面的例子一樣。
    備注:interface{}類型其實是個空接口,即沒有方法的接口。go的每一種類型都實現(xiàn)了該接口。因此,任何其他類型的數(shù)據(jù)都可以賦值給interface{}類型。
  4. 序列化為JSON字符串支持切片類型
    切片類型的數(shù)據(jù)結(jié)構(gòu)可以序列化為JSON字符串。

2 反序列化

2.1 Unmarshal

package main 
import ( 
    "encoding/json" 
    "fmt" 
) 
func main ( ) { 
    var jsonBlob = [ ] byte ( ` [ 
        { "Name" : "Platypus" , "Order" : "Monotremata" } , 
        { "Name" : "Quoll" ,     "Order" : "Dasyuromorphia" } 
    ] ` ) 
    type Animal struct { 
        Name  string 
        Order string 
    } 
    var animals [ ] Animal 
    err := json. Unmarshal ( jsonBlob , & animals ) 
    if err != nil { 
        fmt. Println ( "error:" , err ) 
    } 
    fmt. Printf ( "%+v" , animals ) 
}

結(jié)果輸出:

[{Name:Platypus Order:Monotremata} {Name:Quoll Order:Dasyuromorphia}]

2.2 RawMeaage

package main 
import ( 
    "encoding/json" 
    "fmt" 
    "log" 
) 
func main ( ) { 
    type Color struct { 
        Space string 
        Point json. RawMessage // delay parsing until we know the color space 
    } 
    type RGB struct { 
        R uint8 
        G uint8 
        B uint8 
    } 
    type YCbCr struct { 
        Y   uint8 
        Cb int8 
        Cr int8 
    } 
    var j = [ ] byte ( ` [ 
        { "Space" : "YCbCr" , "Point" : { "Y" : 255 , "Cb" : 0 , "Cr" : -10 } } , 
        { "Space" : "RGB" ,   "Point" : { "R" : 98 , "G" : 218 , "B" : 255 } } 
    ] ` ) 
    var colors [ ] Color 
    err := json. Unmarshal ( j , & colors ) 
    if err != nil { 
        [log ](http://www.opengroup.org/onlinepubs/009695399/functions/log.html). Fatalln ( "error:" , err ) 
    } 
    for _ , c := range colors { 
        var dst interface { } 
        switch c. Space { 
        case "RGB" : 
            dst = new ( RGB ) 
        case "YCbCr" : 
            dst = new ( YCbCr ) 
        } 
        err := json. Unmarshal ( c. Point , dst ) 
        if err != nil { 
            [log ](http://www.opengroup.org/onlinepubs/009695399/functions/log.html). Fatalln ( "error:" , err ) 
        } 
        fmt. Println ( c. Space , dst ) 
    } 
}

輸出結(jié)果:

YCbCr &{255 0 -10}
RGB &{98 218 255}

2.3 Decoder

package main 
import ( 
    "encoding/json" 
    "fmt" 
    "io" 
    "log" 
    "strings" 
) 
func main ( ) { 
    const jsonStream = ` 
        { "Name" : "Ed" , "Text" : "Knock knock." } 
        { "Name" : "Sam" , "Text" : "Who's there?" } 
        { "Name" : "Ed" , "Text" : "Go fmt." } 
        { "Name" : "Sam" , "Text" : "Go fmt who?" } 
        { "Name" : "Ed" , "Text" : "Go fmt yourself!" } 
    ` 
    type Message struct { 
        Name , Text string 
    } 
    dec := json. NewDecoder ( strings. NewReader ( jsonStream ) ) 
    for { 
        var m Message 
        if err := dec. Decode ( & m ) ; err == io. EOF { 
            break 
        } else if err != nil { 
            [log ](http://www.opengroup.org/onlinepubs/009695399/functions/log.html). Fatal ( err ) 
        } 
        fmt. Printf ( "%s: %s \n " , m. Name , m. Text ) 
    } 
}

輸出結(jié)果:

 Ed: Knock knock. 
 Sam: Who's there? 
 Ed: Go fmt. 
 Sam: Go fmt who? 
 Ed: Go fmt yourself! 

2.4 反序列化備注

  1. json字符串解析時,需要一個接收體接收解析后的數(shù)據(jù),且Unmarshal時接收體必須傳遞指針。否則解析雖不報錯,但數(shù)據(jù)無法賦值到接收體中。
  2. json字符串key和對象字段的匹配規(guī)則
    解析時,接收體可自行定義。json串中的key自動在接收體中尋找匹配的字段進行賦值。匹配規(guī)則是:
  • 先查找與key一樣的json標(biāo)簽,找到則賦值給該標(biāo)簽對應(yīng)的變量(如Name)。
  • 沒有json標(biāo)簽的,就從上往下依次查找變量名與key一樣的變量,如Age?;蛘咦兞棵雎源笮懞笈ckey一樣的變量,如HIgh,Class。第一個匹配的就賦值,后面就算有匹配的也忽略。
  • 可解析的變量必須是可導(dǎo)出的,即首字母大寫。不可導(dǎo)出的變量無法被解析(即使json串中有對應(yīng)key的k-v,解析后其值仍為nil,即空值)。
  • 當(dāng)接收體中存在json串中匹配不了的項時,解析會自動忽略該項,該項仍保留原值。如沒有初始值,保留空值nil。
  • interface{}類型的變量,如果解析時沒有明確指定字段的類型,可能得不到自己期望的數(shù)據(jù)結(jié)構(gòu)。例如:解析時不指定變量的具體類型(定義為interface{}類型),json自動將value為復(fù)合結(jié)構(gòu)的數(shù)據(jù)解析為map[string]interface{}類型的項。
  1. interface{}類型變量的類型(reflect.TypeOf(value))都為nil,就是沒有具體類型,這是空接口(interface{}類型)的特點。
  2. 簡單數(shù)據(jù)如基本數(shù)據(jù)類型的數(shù)據(jù)只進行一次json解析。
    復(fù)合數(shù)據(jù)如切片、數(shù)據(jù)結(jié)構(gòu)等數(shù)據(jù),可進行二次甚至多次json解析的,因為它的value也是個可被解析的獨立json。對于”復(fù)合數(shù)據(jù)”,如果接收體中的項被聲明為interface{}類型,go都會默認(rèn)解析成map[string]interface{}類型。如果我們想直接解析到期望的數(shù)據(jù)結(jié)構(gòu)對象中,可以將接收體對應(yīng)的項定義為具體的struct類型。
  3. 保留反序列化中的interface{}類型
    如果不想指定變量為具體的類型,仍想保留interface{}類型,但又希望該變量可以解析到對象中,可以將該變量定義為json.RawMessage類型。如此做之后在接收體中,被聲明為json.RawMessage類型的變量在json解析時,變量值仍保留json的原值,即未被自動解析為map[string]interface{}類型。我們可以對該變量進行二次json解析,因為其值仍是個獨立且可解析的完整json串。我們只需再定義一個新的接收體(具體的結(jié)構(gòu)體)即可。

參考

  1. Package json
  2. JSON and Go
  3. Go的json解析:Marshal與Unmarshal
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容