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 关注
- 108 浏览
添加回答
举报