亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 編程 > Golang > 正文

go json轉換實踐中遇到的坑

2020-04-01 18:50:31
字體:
來源:轉載
供稿:網友

在使用 go 語言開發過程中,經常需要使用到 json 包來進行 json 和 struct 的互相轉換,在使用過程中,遇到了一些需要額外注意的地方,記錄如下。

整數變浮點數問題

假設有一個 Person 結構,其中包含 Age int64 和 Weight float64 兩個字段,現在通過 json 包將 Person 結構轉為 map[string]interface{},代碼如下。

type Person struct { Name string Age int64 Weight float64}func main() { person := Person{  Name: "Wang Wu",  Age: 30,  Weight: 150.07, } jsonBytes, _ := json.Marshal(person) fmt.Println(string(jsonBytes)) var personFromJSON interface{} json.Unmarshal(jsonBytes, &personFromJSON) r := personFromJSON.(map[string]interface{})}

代碼執行到這里看上去一切正常,但是打印一下 map[string]interface{} 就會發現不太對了。

fmt.Println(reflect.TypeOf(r["Age"]).Name()) // float64fmt.Println(reflect.TypeOf(r["Weight"]).Name()) // float64

轉換成 map[string]interface{} 之后,原先的 uint64 和 float64 類型都被轉換成了 float64 類型,這顯然是不符合我們的預期的。

go,json,轉換

查看 json 的規范可以看到,在 json 中是沒有整型和浮點型之分的,所以現在可以理解 json 包中的 Unmarshal 方法轉出的數字類型為什么都是 float64 了,因為根據 json 規范,數字都是同一種類型,那么對應到 go 的類型中最接近的就是 float64 了。

json 包還針對這個問題提供了更好的解決方案,不過需要使用 json.Decoder 來代替 json.Unmarshal 方法,將 json.Unmarhsal 替換如下。

var personFromJSON interface{}decoder := json.NewDecoder(bytes.NewReader(jsonBytes))decoder.UseNumber()decoder.Decode(&personFromJSON)r := personFromJSON.(map[string]interface{})

這種方法首先創建了一個 jsonDecoder,然后調用了 UseNumber 方法,從文檔中可以知道,使用 UseNumber 方法后,json 包會將數字轉換成一個內置的 Number 類型(而不是 float64),這個 Number 類型提供了轉換為 int64、float64 等多個方法。

go,json,轉換

時間格式

對于 json 格式,是沒有時間類型的,日期和時間以 json 格式存儲時,需要轉換為字符串類型。這就帶來了一個問題,日期時間的字符串表示有多種多樣,go 的 json 包支持的是哪一種呢?

使用下面的代碼來輸出 json.Marshal 方法將 Time 類型轉換為字符串后的格式。

type Person struct { Name string Birth time.Time}func main() { person := Person{  Name: "Wang Wu",  Birth: time.Now(), } jsonBytes, _ := json.Marshal(person) fmt.Println(string(jsonBytes)) // {"Name":"Wang Wu","Birth":"2018-12-20T16:22:02.00287617+08:00"}}

根據輸出可以判斷,go 的 json 包使用的是 RFC3339 標準中定義的格式。接下來測試一下 json.Unmarshal 方法所支持的日期時間格式。

dateStr := "2018-10-12"var person PersonjsonStr := fmt.Sprintf("{/"name/":/"Wang Wu/", /"Birth/": /"%s/"}", dateStr)json.Unmarshal([]byte(jsonStr), &person)fmt.Println(person.Birth) // 0001-01-01 00:00:00 +0000 UTC

對于形如 2018-10-12 的字符串,json 包并沒有成功將其解析,接下來我們把 time 包中支持的所有格式都試一下。

go,json,轉換

經過試驗,發現 json.Unmarshal 方法只支持 RFC3339 和 RFC3339Nano 兩種格式的轉換。還有一個需要注意的地方,使用 time.Now() 生成的時間是帶有一個 Monotonic Time 的,經過 json.Marshal 轉換時候,由于 RFC3339 規范里沒有存放 Monotonic Time 的位置,會丟掉這一部分。

對于字段為空的處理

json 包對于空值的處理是一個非常容易出錯的地方,看下面代碼。

type Person struct { Name  string Age  int64 Birth time.Time Children []Person}func main() { person := Person{} jsonBytes, _ := json.Marshal(person) fmt.Println(string(jsonBytes)) // {"Name":"","Age":0,"Birth":"0001-01-01T00:00:00Z","Children":null}}

當 struct 中的字段沒有值時,使用 json.Marshal 方法并不會自動忽略這些字段,而是根據字段的類型輸出了他們的默認空值,這往往和我們的預期不一致,json 包提供了對字段的控制手段,我們可以為字段增加 omitempty tag,這個 tag 會在字段值為零值(int 和 float 類型零值是 0,string 類型零值是 "",對象類型零值是 nil)時,忽略該字段。

type PersonAllowEmpty struct { Name  string    `json:",omitempty"` Age  int64    `json:",omitempty"` Birth time.Time   `json:",omitempty"` Children []PersonAllowEmpty `json:",omitempty"`}func main() { person := PersonAllowEmpty{} jsonBytes, _ := json.Marshal(person) fmt.Println(string(jsonBytes)) // {"Birth":"0001-01-01T00:00:00Z"}}

可以看到,這次輸出的 json 中只有 Birth 字段了,string、int、對象類型的字段,都因為沒有賦值,默認是零值,所以被忽略,對于日期時間類型,由于不可以設置為零值,也就是 0000-00-00 00:00:00,不會被忽略。

需要注意這樣的情況:如果一個人的年齡是 0 (對于剛出生的嬰兒,這個值是合理的),剛好是 int 字段的零值,在添加 omitempty tag 的情況下,年齡字段會被忽略。

如果想要某一個字段在任何情況下都被 json 包忽略,需要使用如下的寫法。

type Person struct { Name  string `json:"-"` Age  int64 `json:"-"` Birth time.Time `json:"-"` Children []string `json:"-"`}func main() { birth, _ := time.Parse(time.RFC3339, "1988-12-02T15:04:27+08:00") person := Person{  Name: "Wang Wu",  Age: 30,  Birth: birth,  Children: []string{}, } jsonBytes, _ := json.Marshal(person) fmt.Println(string(jsonBytes)) // {}}

可以看到,使用 json:"-" 標簽的字段都被忽略了。

補充:golang string轉json的一些坑

先看一段代碼,起作用是把字符串轉換為結構體對應的json

type people struct { name string `json:"name"` age int `json:"age"` id int `json:"id"`} type student struct { people id int `json:"sid"`} func main() { msg := "{/"name/":/"zhangsan/", /"age/":18, /"id/":122463, /"sid/":122464}" var someOne student if err := json.Unmarshal([]byte(msg), &someOne); err == nil {  fmt.Println(someOne)  fmt.Println(someOne.people) } else {  fmt.Println(err) }}

仔細看看,有沒有錯?我只能說,這樣是輸出不出來答案的,賦值錯誤,看下面的運行結果:

go,json,轉換

傷腦筋啊,我仔細看了半天,發現在定義的people和student兩個結構體下邊有綠色的波浪線(我用的vscode),像下邊這樣:

go,json,轉換

鼠標放上去顯示的是:

go,json,轉換

大家都知道,golang中變量聲明成大寫和小寫能引用的范圍是不一樣的,那我就想了,大小寫問題???一臉懵逼把變量名首字母改成了大寫,然后...就行了,代碼變成了下邊這樣:

type people struct { Name string `json:"name"` Age int `json:"age"` ID int `json:"id"`} type student struct { people ID int `json:"sid"`} func main() { msg := "{/"name/":/"zhangsan/", /"age/":18, /"id/":122463, /"sid/":122464}" var someOne student if err := json.Unmarshal([]byte(msg), &someOne); err == nil {  fmt.Println(someOne)  fmt.Println(someOne.people) } else {  fmt.Println(err) }} 

輸出的結果這樣:

go,json,轉換

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持VEVB武林網。


發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
国产亚洲精品91在线| 国产亚洲视频在线观看| 欧美在线视频一区| 欧美亚洲成人xxx| 91国产高清在线| 欧美激情在线一区| 啪一啪鲁一鲁2019在线视频| 日韩电影免费观看在线观看| 国内伊人久久久久久网站视频| 日产精品99久久久久久| 中文字幕在线亚洲| 久久久亚洲欧洲日产国码aⅴ| 亚洲人成五月天| 最近日韩中文字幕中文| 午夜美女久久久久爽久久| 日韩av中文字幕在线免费观看| 欧美激情videoshd| 欧美性猛交xxxxx免费看| 欧美一级淫片aaaaaaa视频| 日韩精品中文字幕有码专区| 国产成人精品免高潮费视频| 欧美成人精品激情在线观看| 日韩欧美999| 国产精品福利网| 亚洲欧美色婷婷| 久久艹在线视频| 亚洲2020天天堂在线观看| 亚洲视频一区二区三区| 中文字幕在线亚洲| 久久久久久免费精品| 亚洲xxxxx电影| 久久97精品久久久久久久不卡| 欧美寡妇偷汉性猛交| 日韩av在线免费| 亚洲精品福利免费在线观看| 欧美在线一级va免费观看| 亚洲电影免费在线观看| 精品人伦一区二区三区蜜桃网站| 欧美激情一区二区三区在线视频观看| 国产91露脸中文字幕在线| 国产91精品网站| 在线免费看av不卡| 欧美日韩成人在线观看| 91精品国产高清久久久久久91| 91在线|亚洲| 国产欧美欧洲在线观看| 一区二区成人精品| 成人激情视频在线观看| 中日韩午夜理伦电影免费| 欧美极品第一页| 国产精品日韩欧美大师| 成人精品aaaa网站| 久久久精品日本| 亚洲欧美制服另类日韩| 国产一区二区视频在线观看| 亚洲精品一区中文| 欧美性猛交xxx| 一区二区三区视频免费在线观看| 欧美大片在线免费观看| 国产视频久久久久久久| 欧美一区二区三区精品电影| 久久久久久久电影一区| 夜夜嗨av色一区二区不卡| 日韩欧美在线观看视频| 岛国av一区二区在线在线观看| 国产精品久久久久久久7电影| 久久成年人免费电影| 欧美另类极品videosbest最新版本| 日韩视频免费看| 国产精品一区二区性色av| 国产精品欧美一区二区三区奶水| 精品无人区乱码1区2区3区在线| 中文字幕欧美精品在线| 亚洲欧美精品伊人久久| 亚洲欧美日韩国产中文| 97色伦亚洲国产| 亚洲精品一区二区三区不| 亚洲色图在线观看| 少妇精69xxtheporn| 亚洲激情中文字幕| 欧洲美女7788成人免费视频| 色噜噜狠狠狠综合曰曰曰| 欧美精品在线免费播放| 日韩精品视频免费专区在线播放| 亚洲色在线视频| 日韩中文字幕在线看| 色婷婷综合久久久久| 欧洲日韩成人av| 日韩网站免费观看| 日韩在线视频线视频免费网站| 亚洲图片欧美日产| 91成人免费观看网站| 中文字幕免费国产精品| 日韩免费视频在线观看| 亚洲电影免费在线观看| 性欧美长视频免费观看不卡| 最近的2019中文字幕免费一页| 亚洲毛片在线观看.| 中文欧美日本在线资源| 一本一道久久a久久精品逆3p| 国产精品露脸av在线| 欧美色xxxx| 欧美大片第1页| 久久国产视频网站| 久久亚洲一区二区三区四区五区高| 国产欧美日韩精品丝袜高跟鞋| 国产午夜精品一区二区三区| 日韩精品黄色网| 国产精品爱啪在线线免费观看| 美女视频黄免费的亚洲男人天堂| 亚洲国产精久久久久久| 精品国产一区二区三区四区在线观看| 国产精品色视频| 久久久免费观看视频| 欧美亚洲免费电影| 欧美激情一区二区三区高清视频| 57pao国产成人免费| 最好看的2019的中文字幕视频| 成人网欧美在线视频| 日韩中文字幕网址| 日韩欧美在线播放| 久久久黄色av| 日韩在线观看视频免费| 国产精品精品视频一区二区三区| 2019亚洲日韩新视频| 国产精品久久久久高潮| 日韩一区二区在线视频| 中文字幕亚洲自拍| 91精品国产自产在线老师啪| 波霸ol色综合久久| 欧美成人在线免费| 亚洲精品久久久久国产| 亚洲美女黄色片| 韩国19禁主播vip福利视频| 久久亚洲精品一区| 成人激情电影一区二区| 欧美又大粗又爽又黄大片视频| 亚洲性猛交xxxxwww| 亚洲成人av片在线观看| 亚洲自拍av在线| 91福利视频在线观看| 91在线观看欧美日韩| 国产精品一区二区三区成人| 欧洲精品毛片网站| 92国产精品视频| 国产精品美女主播在线观看纯欲| 国产视频观看一区| 欧美专区中文字幕| 91免费精品国偷自产在线| 亚洲成人久久电影| 日韩av片永久免费网站| 2021国产精品视频| 亚洲国内精品视频| 国产区精品视频| 日韩中文字幕在线免费观看| 亚洲影院色无极综合| 亚洲欧美在线看| 亚洲国产欧美一区二区三区久久| 91久久久久久久久久| 正在播放国产一区| 精品久久久久久国产| 97视频在线观看免费高清完整版在线观看| 欧美体内谢she精2性欧美| 欧美精品一区在线播放|