我是 Golang 的菜鳥,非常感謝以下方面的任何幫助
我有這個運行良好的代碼片段
var settings CloudSettings
type CloudSettings struct {
...
A1 *bool `json:"cloud.feature1,omitempty"`
...
}
err = json.NewDecoder(request.Body).Decode(&settings)
An attempt to send an invalid string would raise this error:
curl ... -d '{"cloud.feature1" : "Junk"}'
"message":"Error:strconv.ParseBool: parsing \"Junk\": invalid syntax Decoding request body."
現在,我們有一個單獨的LocalSettings
結構,相同的函式需要有條件地處理云/本地設定解碼
于是,代碼改成了:
var settings interface{} = CloudSettings{}
// If the request header says local settings
settings = LocalSettings{}
/* After this change Decode() no longer raises any error for invalid strings and accepts anything */
err = json.NewDecoder(request.Body).Decode(&settings)
所以問題是為什么我會看到這種行為,我將如何解決這個問題?
如果我有 2 個單獨settings
的變數,那么從那時起的整個代碼將被復制,我想避免這種情況
uj5u.com熱心網友回復:
在第二個片段中,您將介面初始化為結構,但傳遞該介面的地址。介面包含一個LocalSettings
orCloudSetting
值,它不能被覆寫,因此解碼器創建一個map[string]interface{}
,將傳遞的介面的值設定為指向它,并解組資料。當您運行第二個片段時,您不會初始化本地設定或云設定。
改變:
settings=&CloudSettings{}
或者
settings=&LocalSettings{}
和
err = json.NewDecoder(request.Body).Decode(settings)
它應該按預期運行
uj5u.com熱心網友回復:
根據您的問題,我假設所有欄位(即使是同名的欄位)在 JSON 標記中都有cloud.
or前綴。local.
如果是這種情況,您可以簡單地將兩個選項嵌入到一個型別中:
type Wrapper struct {
*CloudSettings
*LocalSettings
}
然后解組到這個包裝器型別。JSON 標簽將確保填充正確設定型別的正確欄位:
wrapper := &Wrapper{}
if err := json.NewDecoder(request.Body).Decode(&wrapper); err != nil {
// handle
}
// now to work out which settings were passed:
if wrapper.CloudSettings == nil {
fmt.Println("Local settings provided!")
// use wrapper.CloudSettings
} else {
fmt.Println("Cloud settings provided!")
// use wrapper.LocalSettings
}
游樂場演示
您提到我們希望看到基于標頭值加載的本地設定。您可以簡單地解組有效負載,然后檢查標頭是否與加載的設定型別匹配。如果標頭指定了本地設定,但有效負載包含云設定,則只需回傳錯誤回應。
不過,我在這里假設您的 JSON 標記對于兩種設定型別都是不同的。這并不總是適用,所以如果我的假設不正確,并且某些欄位共享相同的 JSON 標簽,那么自定義 Unmarshal 函式將是可行的方法:
func (w *Wrapper) UnmarshalJSON(data []byte) error {
// say we want to prioritise Local over cloud:
l := LocalSettings{}
if err := json.Unmarshal(data, &l); err == nil {
// we could unmarshal into local without a hitch?
w.CloudSettings = nil // ensure this is blanked out
w.LocalSettings = &l // set local
return nil
}
// we should use cloud settings
c := CloudSettings{}
if err := json.Unmarshal(data, &c); err != nil {
return err
}
w.LocalSettings = nil
w.CloudSettings = &c
return nil
}
這樣,任何沖突都會得到處理,我們可以控制哪些設定優先。同樣,無論 JSON 解組的結果如何,您都可以簡單地交叉檢查標頭值 填充的設定型別,然后從那里獲取。
最后,如果兩種設定型別之間有相當大的重疊,您也可以將有效負載解組為兩種型別,并在包裝??器型別中填充這兩個欄位:
func (w *Wrapper) UnmarshalJSON(data []byte) error {
*w = Wrapper{} // make sure we start with a clean slate
l := LocalSettings{}
var localFail err
if err := json.Unmarshal(data, &l); err == nil {
w.LocalSettings = &l // set local
} else {
localFail = err
}
c := CloudSettings{}
if err := json.Unmarshal(data, &c); err == nil {
w.CloudSettings = &c
} else if localFail != nil { // both unmarshal calls failed
return err // maybe wrap/return custom error
}
return nil // one or more unmarshals were successful
}
這應該夠了吧
轉載請註明出處,本文鏈接:https://www.uj5u.com/net/508329.html
上一篇:如何動態獲取Go中的檔案長度?