痛點
json 是當前最常用的數據傳輸格式之一,純文本,容易使用,方便閱讀,在通信過程中大量被使用。
你是否遇到過json中某個字段填入某種類型都適合而陷入兩難境地? (例如:定義了一個port字段,你卻不知道是填入 8080 ,還是 “8080” 的尷尬局面)
你是否遇到過json反解析報錯是因為填入字段的類型不匹配導致的?例如:
json: cannot unmarshal number into Go struct field Host.port of type string
你是否有json某字段兼容2種或者多種的數據結構的需求?
你是否想讓程序更優雅,更具有適配性,而不在被這些小細節頭痛?
如果你有或者你想,獲取你可以看看這篇文章。
重現問題
我們給了用戶一個json如下:
{
"name":"yulibaozi",
"port":8080
}
但是,業務方卻誤填了”8080”,結果我們程序反解析報錯,導致業務失敗。
json: cannot unmarshal number into Go struct field Host.port of type string
或許你認為這是業務方的問題,但我認為我們可以更優雅的解決這個問題。
如何解決問題
我們先定義了一個結構體
type Host struct {
Name string `json:"name"`
Port Port `json:"port"`
}
心細的你會發現,Port既不是int也不是string類型,而是Port類型,而Port類型是:
type Type int
const (
Int Type = iota
String
)
type Port struct {
Type Type
IntVal int
StrVal string
}
在Port結構體中,我們發現了Type類型, 而Type類型包括了int,string兩種類型。接下來就非常重要了,我們需要實現以下這兩個接口。
json.Unmarshaller interface
json.Marshaller interface
實現代碼如下:
type Port struct {
Type Type
IntVal int
StrVal string
}
// 實現 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)
}
// 實現 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數據:
{"name":"yulibaozi","port":8090}
反解析得到的結構體數據如下:
{Name:yulibaozi Port:{Type:0 IntVal:8090 StrVal:}}
測試反解析string:
給出json數據:
{"name":"yulibaozi","port":"8090"}
反解析得到的結構體數據如下:
{Name:yulibaozi Port:{Type:1 IntVal:0 StrVal:8090}}
測試編碼的json
測試編碼int的結構體如下:
host := Host{
Name: "yulibaozi",
Port: Port{
Type: Int,
IntVal: 8080,
},
}
編碼后的json如下:
{"name":"yulibaozi","port":8080}
測試編碼string的結構體如下:
host := Host{
Name: "yulibaozi",
Port: Port{
Type: String,
StrVal: "8080",
},
}
編碼后的json數據如下:
{"name":"yulibaozi","port":"8080"}
在反編碼測試中,你會發現當json填入的類型不同時,會編碼到結構體中對應的字段中。
在編碼測試中, 具體編碼那個數據是由Type來確定的。
總結
其實,這篇文章只是分享了下json中使用的小技巧,他打破了在使用json時,需要呆板的數據結構的印象,轉而走向了多變,靈活跳脫的風格,其實,這這個小tips的核心在于實現Unmarshaller,Marshaller這兩個結構體,他們的實現是這個分享的關鍵,當然,你可以實現如開篇所說的那樣,json某字段兼容2種及以上結構,當然,你也可以對yaml,toml等進行折騰,都會得到你想要的答案。
好了,以上就是這篇文章的全部內容了,希望本文的內容對大家的學習或者工作具有一定的參考學習價值,如果有疑問大家可以留言交流,謝謝大家對腳本之家的支持。
您可能感興趣的文章:- golang使用json格式實現增刪查改的實現示例
- golang json.Marshal 特殊html字符被轉義的解決方法
- golang結構體與json格式串實例代碼
- golang如何修改json文件內容的方法示例
- golang如何自定義json序列化應用詳解
- golang json性能分析詳解
- golang中json反序列化可能遇到的問題
- Golang map如何生成有序的json數據詳解
- 利用Golang解析json數據的方法示例
- Golang中使用JSON的一些小技巧分享
- golang實現sql結果集以json格式輸出的方法
- Golang 如何解析和生成json