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