最近跟某斯調試一個API介面,介面返回資料是json
格式 ,按文檔描述是一個整型資料,於是定義如下
type Data struct { Api int `json:"api"` }
在入參相同的情況下,第一次調用,得到的結果是:
{"api":1}
然而第二次調用,得到結果卻是:
{"api":"1"}
與對方開發人員溝通後發現這是一個bug,由於流程問題,沒辦法立即修改上線,想想還是我做相容比較好,效果是既能解析於{"api":1}
,也能夠解析{"api":"1"}
,於是我想到了json.Number
,Number類型定義如下
The representation of numbers is similar to that used in most
programming languages. A number is represented in base 10 using
decimal digits. It contains an integer component that may be
prefixed with an optional minus sign, which may be followed by a
fraction part and/or an exponent part. Leading zeros are not
allowed.
簡單翻譯一下:Number
可以表示十進位數,但是前置字元為零資料是不允許的(好吧,此處欠妥,還是看樣本)比如這種012
、-012
等等
我們重新調整資料結構
type Data struct { Api json.Number `json:"api"` }
資料解析
var d Data err := json.Unmarshal([]byte(`{"api":"12"}`), &d)
實際上我們遇到的問題是資料肯定是十進位數,但不確定有沒有""
號,而json.Number
協助抽象了資料這層概念,在確保類型的前提下,由調用方自己決定最終使用的類型
// String returns the literal text of the number.func (n Number) String() string { return string(n) }// Float64 returns the number as a float64.func (n Number) Float64() (float64, error) { return strconv.ParseFloat(string(n), 64)}// Int64 returns the number as an int64.func (n Number) Int64() (int64, error) { return strconv.ParseInt(string(n), 10, 64)}
我可以安全的使用
d.Api.Int64()
從而得到自己想要的類型。
當然,我的問題還可以用RawMessage
類型解決
type Data struct { Api json.RawMessage `json:"api"` }
文檔釋義如下:
// RawMessage is a raw encoded JSON value.// It implements Marshaler and Unmarshaler and can// be used to delay JSON decoding or precompute a JSON encoding.type RawMessage []byte
確定欄位名,拿到json
裡面的未經處理資料值,再轉化成自己想要的類型。
常讀源碼,常讀常新