Golang JSON的進(jìn)階用法實(shí)例講解
痛點(diǎn)
json 是當(dāng)前最常用的數(shù)據(jù)傳輸格式之一,純文本,容易使用,方便閱讀,在通信過程中大量被使用。
你是否遇到過json中某個(gè)字段填入某種類型都適合而陷入兩難境地? (例如:定義了一個(gè)port字段,你卻不知道是填入 8080 ,還是 “8080” 的尷尬局面)
你是否遇到過json反解析報(bào)錯(cuò)是因?yàn)樘钊胱侄蔚念愋筒黄ヅ鋵?dǎo)致的?例如:
json: cannot unmarshal number into Go struct field Host.port of type string
你是否有json某字段兼容2種或者多種的數(shù)據(jù)結(jié)構(gòu)的需求?
你是否想讓程序更優(yōu)雅,更具有適配性,而不在被這些小細(xì)節(jié)頭痛?
如果你有或者你想,獲取你可以看看這篇文章。
重現(xiàn)問題
我們給了用戶一個(gè)json如下:
{ "name":"yulibaozi", "port":8080 }
但是,業(yè)務(wù)方卻誤填了”8080”,結(jié)果我們程序反解析報(bào)錯(cuò),導(dǎo)致業(yè)務(wù)失敗。
json: cannot unmarshal number into Go struct field Host.port of type string
或許你認(rèn)為這是業(yè)務(wù)方的問題,但我認(rèn)為我們可以更優(yōu)雅的解決這個(gè)問題。
如何解決問題
我們先定義了一個(gè)結(jié)構(gòu)體
type Host struct { Name string `json:"name"` Port Port `json:"port"` }
心細(xì)的你會發(fā)現(xiàn),Port既不是int也不是string類型,而是Port類型,而Port類型是:
type Type int const ( Int Type = iota String ) type Port struct { Type Type IntVal int StrVal string }
在Port結(jié)構(gòu)體中,我們發(fā)現(xiàn)了Type類型, 而Type類型包括了int,string兩種類型。接下來就非常重要了,我們需要實(shí)現(xiàn)以下這兩個(gè)接口。
json.Unmarshaller interface json.Marshaller interface
實(shí)現(xiàn)代碼如下:
type Port struct { Type Type IntVal int StrVal string } // 實(shí)現(xiàn) json.Unmarshaller 接口 func (port *Port) UnmarshalJSON(value []byte) error { if value[0] == '"' { port.Type = String return json.Unmarshal(value, &port.StrVal) } port.Type = Int return json.Unmarshal(value, &port.IntVal) } // 實(shí)現(xiàn) json.Marshaller 接口 func (port Port) MarshalJSON() ([]byte, error) { switch port.Type { case Int: return json.Marshal(port.IntVal) case String: return json.Marshal(port.StrVal) default: return []byte{}, fmt.Errorf("impossible Port.Type") } }
接下來測試:
測試反解析
測試反解析int
給出json數(shù)據(jù):
{"name":"yulibaozi","port":8090}
反解析得到的結(jié)構(gòu)體數(shù)據(jù)如下:
&{Name:yulibaozi Port:{Type:0 IntVal:8090 StrVal:}}
測試反解析string:
給出json數(shù)據(jù):
{"name":"yulibaozi","port":"8090"}
反解析得到的結(jié)構(gòu)體數(shù)據(jù)如下:
&{Name:yulibaozi Port:{Type:1 IntVal:0 StrVal:8090}}
測試編碼的json
測試編碼int的結(jié)構(gòu)體如下:
host := &Host{ Name: "yulibaozi", Port: Port{ Type: Int, IntVal: 8080, }, }
編碼后的json如下:
{"name":"yulibaozi","port":8080}
測試編碼string的結(jié)構(gòu)體如下:
host := &Host{ Name: "yulibaozi", Port: Port{ Type: String, StrVal: "8080", }, }
編碼后的json數(shù)據(jù)如下:
{"name":"yulibaozi","port":"8080"}
在反編碼測試中,你會發(fā)現(xiàn)當(dāng)json填入的類型不同時(shí),會編碼到結(jié)構(gòu)體中對應(yīng)的字段中。
在編碼測試中, 具體編碼那個(gè)數(shù)據(jù)是由Type來確定的。
總結(jié)
其實(shí),這篇文章只是分享了下json中使用的小技巧,他打破了在使用json時(shí),需要呆板的數(shù)據(jù)結(jié)構(gòu)的印象,轉(zhuǎn)而走向了多變,靈活跳脫的風(fēng)格,其實(shí),這這個(gè)小tips的核心在于實(shí)現(xiàn)Unmarshaller,Marshaller這兩個(gè)結(jié)構(gòu)體,他們的實(shí)現(xiàn)是這個(gè)分享的關(guān)鍵,當(dāng)然,你可以實(shí)現(xiàn)如開篇所說的那樣,json某字段兼容2種及以上結(jié)構(gòu),當(dāng)然,你也可以對yaml,toml等進(jìn)行折騰,都會得到你想要的答案。
好了,以上就是這篇文章的全部內(nèi)容了,希望本文的內(nèi)容對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,如果有疑問大家可以留言交流,謝謝大家對腳本之家的支持。
- golang使用json格式實(shí)現(xiàn)增刪查改的實(shí)現(xiàn)示例
- golang json.Marshal 特殊html字符被轉(zhuǎn)義的解決方法
- golang結(jié)構(gòu)體與json格式串實(shí)例代碼
- golang如何修改json文件內(nèi)容的方法示例
- golang如何自定義json序列化應(yīng)用詳解
- golang json性能分析詳解
- golang中json反序列化可能遇到的問題
- Golang map如何生成有序的json數(shù)據(jù)詳解
- 利用Golang解析json數(shù)據(jù)的方法示例
- Golang中使用JSON的一些小技巧分享
- golang實(shí)現(xiàn)sql結(jié)果集以json格式輸出的方法
- Golang 如何解析和生成json
相關(guān)文章
Go語言驅(qū)動(dòng)低代碼應(yīng)用引擎工具Yao開發(fā)管理系統(tǒng)
這篇文章主要為大家介紹了Go語言驅(qū)動(dòng)低代碼應(yīng)用引擎工具Yao開發(fā)管理系統(tǒng)使用詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-06-06Go語言標(biāo)準(zhǔn)輸入輸出庫的基本使用教程
輸入輸出在任何一門語言中都必須提供的一個(gè)功能,下面這篇文章主要給大家介紹了關(guān)于Go語言標(biāo)準(zhǔn)輸入輸出庫的基本使用,文中通過實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下2022-02-02Golang中空的切片轉(zhuǎn)化成 JSON 后變?yōu)?nbsp;null 問題的解決方案
在 Golang 中,經(jīng)常需要將其他類型(例如 slice、map、struct 等類型)的數(shù)據(jù)轉(zhuǎn)化為 JSON 格式,有時(shí)候轉(zhuǎn)化的結(jié)果并不是預(yù)期中的,例如將一個(gè)空的切片轉(zhuǎn)化為 JSON 時(shí),會變成"null",所以本文將給大家介紹一下解決方法,需要的朋友可以參考下2023-09-09golang interface判斷為空nil的實(shí)現(xiàn)代碼
這篇文章主要介紹了golang interface判斷為空nil的實(shí)現(xiàn)代碼,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧2021-04-04