引言
這個問題出現在決議一個json的組態檔時,排錯了很久,最后和狗勛一起解決了這個奇怪的問題,
正文
其實這個問題并不難,因為Golang自帶json包,所以我們要做的其實就是在需要決議的結構體中加上相應的標簽就可以了,但是可能會出現一些隱性的bug,且沒有任何的報錯,
我一共遇到了兩種問題,其中第一種比較好解決,網上的解決方案也大多是描述第一種問題;但是第二種問題就非常的蹊蹺了,因為在專案中出現了問題,寫了一個測驗代碼并沒有復現成功,
第一種解決方案:結構體需要決議的相應欄位應該大寫,
我們先來看一段代碼:
---test.json
{
"page": 1,
"fruits": ["apple", "peach"]
}
---test_json.go
type response struct {
number int
Page int `json:page`
fruits []string `json:fruits`
}
func main(){
data, _ := io.ReadFile("test.json")
res := response{}
json.Unmarshal(data, &res)
fmt.Println(res)
}
ouput:
{0 1 []}
我們可以看到在首字母小寫時出現問題,解決方案也很容易,就是需要把欄位開頭改成大寫,當然這樣是有弊端的,因為一般需要從組態檔中讀取的欄位一般都是與配置相關的,而這些一般應該設定成private的,C++就可以很好的解決,這也許就是go不如C++自由的原因吧,當然這可能也是C++沒有類似go這樣json庫的原因吧,
第二種解決方案:就是Goland的json決議要么加雙引號,要么不加雙引號名稱中不能帶下劃線,即_,
也就是上面的結構體應該寫成這樣:
type response struct {
number int
Page int `json:"page"`
fruits []string `json:"fruits"`
}
也就是這樣子,雖然這個測驗代碼不加雙引號也可以正確決議出slice,但是在專案中的結構體卻出現了問題,我把專案中的結構體中帶json欄位的提取出來就可以復現錯誤了:
---test.json
{
"servers_address": ["localhost:8901","localhost:8902"],
"myport" : ":8900",
"maxreries" : 13,
"timeout_entry" : 200
}
---test_json.go
type response struct {
Maxreries int `json:maxreries`
ServersAddress []string `json:servers_address`
MyPort string `json:myport`
TimeOutEntry int `json:timeout_entry`
}
func main(){
data, _ := io.ReadFile("test.json")
res := response{}
json.Unmarshal(data, &res)
fmt.Println(res)
}
ouput:
{13 [] :8900 0}
我們可以看到決議失敗,ServersAddress和TimeOutEntry決議失敗,這已經不是決議slice失敗了,int也出現問題,讓我們加上雙引號看看:
ouput:
{13 [localhost:8901 localhost:8902] :8900 200}
我們可以看到決議成功,
那么不加雙引號為什么有時可以決議成功,有時不可以呢?因為已經不是決議slice失敗了,而決議int也同樣出現了錯誤,
觀察兩個出現問題的欄位,發現它們有一個共同點,就是json標簽中都帶了_,讓我們去掉執行看看:
{13 [localhost:8901 localhost:8902] :8900 200}
排查出錯誤!就是Golang的json決議在結構體json標簽不加雙引號時無法決議名稱帶_的欄位!
這個問題估計是一個極其隱式的問題,官方檔案中也沒有描述,網上在此之前也沒有一篇文章描述這個問題,希望看完這篇文章能幫助你解決這個令人困惑不以的問題,
參考:
- 博文《Go by Example: JSON》
- 檔案《func Unmarshal》
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/187989.html
標籤:其他
