2 回答

TA貢獻1796條經驗 獲得超4個贊
在第二個片段中,您有一個初始化為結構的接口,但傳遞了該接口的地址。該接口包含一個不能被覆蓋的LocalSettings
orCloudSetting
值,因此解碼器創建一個map[string]interface{}
,將傳遞的接口的值設置為指向該值,然后解組數據。當您運行第二個代碼段時,您不會初始化本地設置或云設置。
改變:
settings=&CloudSettings{}
或者
settings=&LocalSettings{}
和
err = json.NewDecoder(request.Body).Decode(settings)
它應該表現得像預期的那樣

TA貢獻1802條經驗 獲得超5個贊
根據您的問題,我假設所有字段(即使是具有相同名稱的字段)在 JSON 標記中都有一個cloud.或前綴。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
}
這應該夠了吧
- 2 回答
- 0 關注
- 161 瀏覽
添加回答
舉報