gpt4 book ai didi

go - 为什么在有 Unmarshal 实现时不解码嵌入式结构?

转载 作者:IT王子 更新时间:2023-10-29 02:05:27 25 4
gpt4 key购买 nike

我有一个 ServiceAccount 类型,它嵌入了另外两种类型(用户和策略)。然而,由于 Policy 类型的 Unmarshaler 实现,似乎完全忽略了 User 类型的字段。 这种行为有什么充分的理由吗?对我来说这看起来像是一个错误,因为 json 包可以通过反射看到我们嵌入了两种类型,而不仅仅是 Policy 类型。

我知道我也可以通过在 ServiceAccount 类型上实现 Unmarshaler 接口(interface)来“解决”这个问题。

package main

import (
"encoding/json"
"fmt"

)
type ServiceAccount struct {
User
Policy
}
type User struct {
UserID string `json:"userID"`
}

type Policy struct {
Scopes string `json:"scopes,omitempty"`
}

// PolicyRaw is the Policy type as received from client.
type PolicyRaw struct {
Scopes string `json:"scopes,omitempty"`
}

func main() {
s := `{"userID":"xyz", "scopes":"some scopes"}`

srvAcc := &ServiceAccount{}
if err := json.Unmarshal([]byte(s), srvAcc); err != nil {
panic(err)
}
fmt.Printf("srvAcc %v", *srvAcc)
}

func (p *Policy) UnmarshalJSON(b []byte) error {
pr := new(PolicyRaw)
if err := json.Unmarshal(b, pr); err != nil {
return err
}
p.Scopes = pr.Scopes
return nil
}

Execute

最佳答案

我不认为这是一个错误,而只是接口(interface)和嵌入的工作方式。它恰好不是您在这里想要/期望的。

json.Unmarshal 通过 this line 计算出使用 UnmarshalJSON 方法:

    if u, ok := v.Interface().(Unmarshaler); ok

如您所知,如果某物具有正确的方法集(如 *Policy*ServiceAccount 所做的),它就会实现一个接口(interface)。因此,预计外部类型的 JSON 解码只会调用适当的方法并认为它已完成。

有趣的是,如果您要试验并添加一个虚拟方法,例如:

func (u *User) UnmarshalJSON([]byte) error {return errors.New("not impl")}

虽然 *User*Policy 现在都实现了接口(interface),*ServiceAccount 将不再实现该接口(interface)。如果您尝试显式调用 srvAcc.UnmarshalJSON,那么原因很明显,这将给出编译器错误“不明确的选择器 srvAcc.UnmarshalJSON”。如果没有这样的调用,代码是合法的,并且该方法只是从方法集中排除。

所以我认为解决方案是以下之一:

  • 如果您想编码结果,请不要嵌入实现 json.Unmarshaller 的东西,例如请改用命名字段。
  • 确保在进行此类嵌入时自己为外部类型显式实现 json.Unmarshaller(例如,将 UnmarshalJSON 方法添加到 *ServiceAccount ).
  • 确保至少有两个嵌入的东西实现json.Unmarshaller,然后 它们将单独工作 ¹,但“外部”类型将获得默认行为。<

最后一个选项对我来说似乎是一个 hack。 (顺便说一句,可以故意用类似的东西来完成:

    type ServiceAccount struct {
User
Policy
dummyMarshaller
}

type dummyMarshaller struct{}
func (dummyMarshaller) MarshalJSON([]byte) error {panic("ouch")}

但这对我来说看起来真的很老套)。

另见:

¹ Further testing显示解码此类匿名(即嵌入式字段),它们的 UnmarshalJSON 方法不会被调用。

关于go - 为什么在有 Unmarshal 实现时不解码嵌入式结构?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28976458/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com