1 回答
TA贡献1816条经验 获得超6个赞
我不认为这是一个错误,而只是接口和嵌入的工作方式。它只是碰巧不是您想要/期望的。
json.Unmarshal
弄清楚UnmarshalJSON
通过这一行使用该方法:
if u, ok := v.Interface().(Unmarshaler); ok
如您所知,如果某个接口具有正确的方法集 which*Policy
和*ServiceAccount
do,则它会实现接口。因此,预计外部类型的 JSON 解码只会调用适当的方法并认为它已完成。
有趣的是,如果您要进行试验并添加一个虚拟方法,例如:
func (u *User) UnmarshalJSON([]byte) error {return errors.New("not impl")}
然后虽然*User
和*Policy
现在都实现了接口,但 *ServiceAccount
将不再实现该接口。原因很明显,如果您尝试并显式调用srvAcc.UnmarshalJSON
它,则会给出“模棱两可的选择器 srvAcc.UnmarshalJSON ”的编译器错误。如果没有这样的调用,代码是合法的,并且该方法只是从方法集中排除。
所以我认为解决方案是以下之一:
json.Unmarshaller
如果您想编组结果,请不要嵌入实现的东西,例如使用命名字段。json.Unmarshaller
在进行此类嵌入时,请确保您自己为外部类型显式实现(例如,向 中添加UnmarshalJSON
方法*ServiceAccount
)。确保至少实现了两个嵌入的东西
json.Unmarshaller
,然后它们将单独工作¹,但“外部”类型将获得默认行为。
最后一个选项对我来说似乎是一个黑客。(顺便说一句,可以故意这样做:
type ServiceAccount struct {
User
Policy
dummyMarshaller
}
type dummyMarshaller struct{}
func (dummyMarshaller) MarshalJSON([]byte) error {panic("ouch")}
但这对我来说看起来真的很糟糕)。
也可以看看:
https://golang.org/ref/spec#Struct_types
https://golang.org/doc/effective_go.html#embedding
¹进一步的测试表明,解码此类匿名(即嵌入字段),它们的UnmarshalJSON方法不会被调用。
- 1 回答
- 0 关注
- 173 浏览
添加回答
举报