Golang中omitempty關(guān)鍵字的具體實(shí)現(xiàn)
用法
熟悉 Golang 的朋友對(duì)于 json 和 struct 之間的轉(zhuǎn)換一定不陌生,為了將代碼中的結(jié)構(gòu)體與 json 數(shù)據(jù)解耦,通常我們會(huì)在結(jié)構(gòu)體的 field 類型后加上解釋說(shuō)明,例如在表示一個(gè)地址的時(shí)候, json 數(shù)據(jù)如下所示
{ "street": "200 Larkin St", "city": "San Francisco", "state": "CA", "zipcode": "94102" }
與之相對(duì)應(yīng)的 Golang 結(jié)構(gòu)體表示可能是這個(gè)樣子的
type address struct { Street string `json:"street"` // 街道 Ste string `json:"suite"` // 單元(可以不存在) City string `json:"city"` // 城市 State string `json:"state"` // 州/省 Zipcode string `json:"zipcode"` // 郵編 }
這樣無(wú)論代碼中的變量如何改變,我們都能成功將 json 數(shù)據(jù)解析出來(lái),獲得正確的街道,城市等信息,到目前為止一切正常。但如果我們想要將地址結(jié)構(gòu)體恢復(fù)成 json 格式時(shí),問(wèn)題就來(lái)了。比方說(shuō)我們用下面這段代碼讀取了地址 json ,然后根據(jù)業(yè)務(wù)邏輯處理了之后恢復(fù)成正常的 json 打印出來(lái)
func main() { ? ? ? ? data := `{ ? ? ? ? "street": "200 Larkin St", ? ? ? ? "city": "San Francisco", ? ? ? ? "state": "CA", ? ? ? ? "zipcode": "94102" ? ? }` ? ? addr := new(address) ? ? json.Unmarshal([]byte(data), &addr) ? ? ? ? // 處理了一番 addr 變量... ? ? addressBytes, _ := json.MarshalIndent(addr, "", " ? ?") ? ? fmt.Printf("%s\n", string(addressBytes)) }
這段代碼的輸出是
{ "street": "200 Larkin St", "suite": "", "city": "San Francisco", "state": "CA", "zipcode": "94102" }
多了一行 "suite": "", ,而這則信息在原本的 json 數(shù)據(jù)中是沒(méi)有的(在美國(guó)的地址中,如果不是群租公寓或者共享辦公樓, suite 這一條不存在很正常,人們直接用街道門牌號(hào)來(lái)表示地址就足夠了),但我們更希望的是,在一個(gè)地址有 suite 號(hào)碼的時(shí)候輸出,不存在 suite 的時(shí)候就不輸出,幸運(yùn)的是,我們可以在 Golang 的結(jié)構(gòu)體定義中添加 omitempty 關(guān)鍵字,來(lái)表示這條信息如果沒(méi)有提供,在序列化成 json 的時(shí)候就不要包含其默認(rèn)值。稍作修改,地址結(jié)構(gòu)體就變成了
type address struct { Street string `json:"street"` Ste string `json:"suite,omitempty"` City string `json:"city"` State string `json:"state"` Zipcode string `json:"zipcode"` }
重新運(yùn)行,即可得到正確的結(jié)果。
陷阱
帶來(lái)方便的同時(shí),使用 omitempty 也有些小陷阱,一個(gè)是該關(guān)鍵字無(wú)法忽略掉嵌套結(jié)構(gòu)體。還是拿地址類型說(shuō)事,這回我們想要往地址結(jié)構(gòu)體中加一個(gè)新 field 來(lái)表示經(jīng)緯度,如果沒(méi)有缺乏相關(guān)的數(shù)據(jù),暫時(shí)可以忽略。新的 struct 定義如下所示
type address struct { ? ? Street ? ? string ? ? `json:"street"` ? ? Ste ? ? ? ?string ? ? `json:"suite,omitempty"` ? ? City ? ? ? string ? ? `json:"city"` ? ? State ? ? ?string ? ? `json:"state"` ? ? Zipcode ? ?string ? ? `json:"zipcode"` ? ? Coordinate coordinate `json:"coordinate,omitempty"` } type coordinate struct { ? ? Lat float64 `json:"latitude"` ? ? Lng float64 `json:"longitude"` }
讀入原來(lái)的地址數(shù)據(jù),處理后序列化輸出,我們就會(huì)發(fā)現(xiàn)即使加上了 omitempty 關(guān)鍵字,輸出的 json 還是帶上了一個(gè)空的坐標(biāo)信息
{ "street": "200 Larkin St", "city": "San Francisco", "state": "CA", "zipcode": "94102", "coordinate": { "latitude": 0, "longitude": 0 } }
為了達(dá)到我們想要的效果,可以把坐標(biāo)定義為指針類型,這樣 Golang 就能知道一個(gè)指針的“空值”是多少了,否則面對(duì)一個(gè)我們自定義的結(jié)構(gòu), Golang 是猜不出我們想要的空值的。于是有了如下的結(jié)構(gòu)體定義
type address struct { ? ? Street ? ? string ? ? ?`json:"street"` ? ? Ste ? ? ? ?string ? ? ?`json:"suite,omitempty"` ? ? City ? ? ? string ? ? ?`json:"city"` ? ? State ? ? ?string ? ? ?`json:"state"` ? ? Zipcode ? ?string ? ? ?`json:"zipcode"` ? ? Coordinate *coordinate `json:"coordinate,omitempty"` } type coordinate struct { ? ? Lat float64 `json:"latitude"` ? ? Lng float64 `json:"longitude"` }
相應(yīng)的輸出為
{ "street": "200 Larkin St", "city": "San Francisco", "state": "CA", "zipcode": "94102" }
另一個(gè)“陷阱”是,對(duì)于用 omitempty 定義的 field ,如果給它賦的值恰好等于默認(rèn)空值的話,在轉(zhuǎn)為 json 之后也不會(huì)輸出這個(gè) field 。比如說(shuō)上面定義的經(jīng)緯度坐標(biāo)結(jié)構(gòu)體,如果我們將經(jīng)緯度兩個(gè) field 都加上 omitempty
type coordinate struct { Lat float64 `json:"latitude,omitempty"` Lng float64 `json:"longitude,omitempty"` }
然后我們對(duì)非洲幾內(nèi)亞灣的“原點(diǎn)坐標(biāo)”非常感興趣,于是編寫了如下代碼
func main() { ? ? cData := `{ ? ? ? ? "latitude": 0.0, ? ? ? ? "longitude": 0.0 ? ? }` ? ? c := new(coordinate) ? ? json.Unmarshal([]byte(cData), &c) ? ? ? ? // 具體處理邏輯... ? ? coordinateBytes, _ := json.MarshalIndent(c, "", " ? ?") ? ? fmt.Printf("%s\n", string(coordinateBytes)) }
最終我們得到了一個(gè)
{}
這個(gè)坐標(biāo)消失不見(jiàn)了!但我們的設(shè)想是,如果一個(gè)地點(diǎn)沒(méi)有經(jīng)緯度信息,則懸空,這沒(méi)有問(wèn)題,但對(duì)于“原點(diǎn)坐標(biāo)”,我們?cè)诖_切知道它的經(jīng)緯度的情況下,(0.0, 0.0)仍然被忽略了。正確的寫法也是將結(jié)構(gòu)體內(nèi)的定義改為指針
type coordinate struct { ? ? Lat *float64 `json:"latitude,omitempty"` ? ? Lng *float64 `json:"longitude,omitempty"` }
這樣空值就從 float64 的 0.0 變?yōu)榱酥羔橆愋偷?nil ,我們就能看到正確的經(jīng)緯度輸出。
{ "latitude": 0, "longitude": 0 }
P.S. 本文中拿來(lái)作示例的地址是舊金山亞洲藝術(shù)博物館的地址,藏品豐富,上到夏商周,下至明清的文物都能看到,幾年前第一次去參觀,很是喜歡,印象深刻。
到此這篇關(guān)于Golang中omitempty關(guān)鍵字的具體實(shí)現(xiàn)的文章就介紹到這了,更多相關(guān)Golang omitempty 內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
go語(yǔ)言實(shí)現(xiàn)字符串base64編碼的方法
這篇文章主要介紹了go語(yǔ)言實(shí)現(xiàn)字符串base64編碼的方法,實(shí)例分析了Go語(yǔ)言操作字符串的技巧及base64編碼的使用技巧,需要的朋友可以參考下2015-03-03golang開(kāi)啟mod后import報(bào)紅的簡(jiǎn)單解決方案
這篇文章主要給大家介紹了關(guān)于golang開(kāi)啟mod后import報(bào)紅的簡(jiǎn)單解決方案,文中通過(guò)圖文將解決的辦法介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2024-01-01Go?處理大數(shù)組使用?for?range?和?for?循環(huán)的區(qū)別
這篇文章主要介紹了Go處理大數(shù)組使用for?range和for循環(huán)的區(qū)別,對(duì)于遍歷大數(shù)組而言,for循環(huán)能比f(wàn)or?range循環(huán)更高效與穩(wěn)定,這一點(diǎn)在數(shù)組元素為結(jié)構(gòu)體類型更加明顯,下文具體分析感興趣得小伙伴可以參考一下2022-05-05Go語(yǔ)言如何實(shí)現(xiàn)TCP通信詳解
go里面實(shí)現(xiàn)tcp沒(méi)有像之前寫的C++那些那么麻煩,在C++里面要先創(chuàng)建套接字,然后綁定ip地址,go里面直接就一個(gè)函數(shù)建立套接字,然后在進(jìn)行通信就可以了,下面這篇文章主要給大家介紹了關(guān)于Go語(yǔ)言如何實(shí)現(xiàn)TCP通信的相關(guān)資料,需要的朋友可以參考下2023-01-01Go Uber靜態(tài)分析工具NilAway使用初體驗(yàn)
這篇文章主要介紹了Go Uber靜態(tài)分析工具NilAway使用詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2024-01-01詳解Go語(yǔ)言如何解決map并發(fā)安全問(wèn)題
常說(shuō)go語(yǔ)言是一門并發(fā)友好的語(yǔ)言,對(duì)于并發(fā)操作總會(huì)在編譯期完成安全檢查,所以這篇文章我們就來(lái)聊聊go語(yǔ)言是如何解決map這個(gè)數(shù)據(jù)結(jié)構(gòu)的線程安全問(wèn)題吧2024-04-04