Golang的對(duì)象和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對(duì)象等边败。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,如ID断傲,Colors脱吱。
  3. 可以序列化為JSON的類型和限制
  • 基本數(shù)據(jù)類型和普通的結(jié)構(gòu)體都可以序列化,如bool類型也是可以直接轉(zhuǎn)換為json的value值艳悔。循環(huán)的數(shù)據(jù)結(jié)構(gòu)不能序列化為JSON急凰,它會(huì)導(dǎo)致marshal陷入死循環(huán)。
  • channel猜年,complex 以及函數(shù)不能被編碼json字符串抡锈。
  1. 指針變量編碼時(shí)自動(dòng)轉(zhuǎn)換為它所指向的值
    指針變量編碼時(shí)自動(dòng)轉(zhuǎn)換為它所指向的值,與直接定義為結(jié)構(gòu)體對(duì)象類型效果一樣乔外,只不過指針更快床三,且能節(jié)省內(nèi)存空間。
  2. 對(duì)象序列化為json后就成為純粹的字符串杨幼。
  3. 包含通用類型的對(duì)象序列化
    成員變量都是已知的類型撇簿,只能接收指定的類型,比如string類型的Name只能賦值string類型的數(shù)據(jù)差购。
    有時(shí)為了通用性或使代碼簡(jiǎn)潔四瘫,我們希望有一種類型可以接受各種類型的數(shù)據(jù),并序列化為json欲逃,就需要使用interface{}類型找蜜。無論是stringint稳析,bool洗做,還是指針類型等,都可賦值給interface{}類型彰居,且正常編碼诚纸,效果與前面的例子一樣。
    備注:interface{}類型其實(shí)是個(gè)空接口陈惰,即沒有方法的接口畦徘。go的每一種類型都實(shí)現(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í),需要一個(gè)接收體接收解析后的數(shù)據(jù)掘剪,且Unmarshal時(shí)接收體必須傳遞指針平委。否則解析雖不報(bào)錯(cuò)痊乾,但數(shù)據(jù)無法賦值到接收體中施逾。
  2. json字符串key和對(duì)象字段的匹配規(guī)則
    解析時(shí),接收體可自行定義旗闽。json串中的key自動(dòng)在接收體中尋找匹配的字段進(jìn)行賦值匾鸥。匹配規(guī)則是:
  • 先查找與key一樣的json標(biāo)簽蜡塌,找到則賦值給該標(biāo)簽對(duì)應(yīng)的變量(如Name)。
  • 沒有json標(biāo)簽的勿负,就從上往下依次查找變量名與key一樣的變量馏艾,如Age∨洌或者變量名忽略大小寫后與key一樣的變量琅摩,如HIgh,Class锭硼。第一個(gè)匹配的就賦值房资,后面就算有匹配的也忽略。
  • 可解析的變量必須是可導(dǎo)出的檀头,即首字母大寫轰异。不可導(dǎo)出的變量無法被解析(即使json串中有對(duì)應(yīng)key的k-v,解析后其值仍為nil,即空值)暑始。
  • 當(dāng)接收體中存在json串中匹配不了的項(xiàng)時(shí)搭独,解析會(huì)自動(dòng)忽略該項(xiàng),該項(xiàng)仍保留原值廊镜。如沒有初始值戳稽,保留空值nil。
  • interface{}類型的變量期升,如果解析時(shí)沒有明確指定字段的類型,可能得不到自己期望的數(shù)據(jù)結(jié)構(gòu)互躬。例如:解析時(shí)不指定變量的具體類型(定義為interface{}類型)播赁,json自動(dòng)將value為復(fù)合結(jié)構(gòu)的數(shù)據(jù)解析為map[string]interface{}類型的項(xiàng)。
  1. interface{}類型變量的類型(reflect.TypeOf(value))都為nil吼渡,就是沒有具體類型容为,這是空接口(interface{}類型)的特點(diǎn)。
  2. 簡(jiǎn)單數(shù)據(jù)如基本數(shù)據(jù)類型的數(shù)據(jù)只進(jìn)行一次json解析。
    復(fù)合數(shù)據(jù)如切片坎背、數(shù)據(jù)結(jié)構(gòu)等數(shù)據(jù)替劈,可進(jìn)行二次甚至多次json解析的,因?yàn)樗膙alue也是個(gè)可被解析的獨(dú)立json得滤。對(duì)于”復(fù)合數(shù)據(jù)”陨献,如果接收體中的項(xiàng)被聲明為interface{}類型,go都會(huì)默認(rèn)解析成map[string]interface{}類型懂更。如果我們想直接解析到期望的數(shù)據(jù)結(jié)構(gòu)對(duì)象中眨业,可以將接收體對(duì)應(yīng)的項(xiàng)定義為具體的struct類型。
  3. 保留反序列化中的interface{}類型
    如果不想指定變量為具體的類型沮协,仍想保留interface{}類型龄捡,但又希望該變量可以解析到對(duì)象中,可以將該變量定義為json.RawMessage類型慷暂。如此做之后在接收體中聘殖,被聲明為json.RawMessage類型的變量在json解析時(shí),變量值仍保留json的原值行瑞,即未被自動(dòng)解析為map[string]interface{}類型奸腺。我們可以對(duì)該變量進(jìn)行二次json解析,因?yàn)槠渲等允莻€(gè)獨(dú)立且可解析的完整json串蘑辑。我們只需再定義一個(gè)新的接收體(具體的結(jié)構(gòu)體)即可洋机。

參考

  1. Package json
  2. JSON and Go
  3. Go的json解析:Marshal與Unmarshal
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市洋魂,隨后出現(xiàn)的幾起案子绷旗,更是在濱河造成了極大的恐慌,老刑警劉巖副砍,帶你破解...
    沈念sama閱讀 212,454評(píng)論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件衔肢,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡豁翎,警方通過查閱死者的電腦和手機(jī)角骤,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,553評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來心剥,“玉大人邦尊,你說我怎么就攤上這事∮派眨” “怎么了蝉揍?”我有些...
    開封第一講書人閱讀 157,921評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)畦娄。 經(jīng)常有香客問我又沾,道長(zhǎng)弊仪,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,648評(píng)論 1 284
  • 正文 為了忘掉前任杖刷,我火速辦了婚禮励饵,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘滑燃。我一直安慰自己役听,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,770評(píng)論 6 386
  • 文/花漫 我一把揭開白布不瓶。 她就那樣靜靜地躺著禾嫉,像睡著了一般。 火紅的嫁衣襯著肌膚如雪蚊丐。 梳的紋絲不亂的頭發(fā)上熙参,一...
    開封第一講書人閱讀 49,950評(píng)論 1 291
  • 那天,我揣著相機(jī)與錄音麦备,去河邊找鬼孽椰。 笑死,一個(gè)胖子當(dāng)著我的面吹牛凛篙,可吹牛的內(nèi)容都是我干的黍匾。 我是一名探鬼主播,決...
    沈念sama閱讀 39,090評(píng)論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼呛梆,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼锐涯!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起填物,我...
    開封第一講書人閱讀 37,817評(píng)論 0 268
  • 序言:老撾萬榮一對(duì)情侶失蹤纹腌,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后滞磺,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體升薯,經(jīng)...
    沈念sama閱讀 44,275評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,592評(píng)論 2 327
  • 正文 我和宋清朗相戀三年击困,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了涎劈。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,724評(píng)論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡阅茶,死狀恐怖蛛枚,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情脸哀,我是刑警寧澤坤候,帶...
    沈念sama閱讀 34,409評(píng)論 4 333
  • 正文 年R本政府宣布,位于F島的核電站企蹭,受9級(jí)特大地震影響白筹,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜谅摄,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,052評(píng)論 3 316
  • 文/蒙蒙 一徒河、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧送漠,春花似錦顽照、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,815評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至爷狈,卻和暖如春植影,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背涎永。 一陣腳步聲響...
    開封第一講書人閱讀 32,043評(píng)論 1 266
  • 我被黑心中介騙來泰國打工思币, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人羡微。 一個(gè)月前我還...
    沈念sama閱讀 46,503評(píng)論 2 361
  • 正文 我出身青樓谷饿,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國和親妈倔。 傳聞我的和親對(duì)象是個(gè)殘疾皇子博投,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,627評(píng)論 2 350

推薦閱讀更多精彩內(nèi)容