当前位置: 首页 > 面试题库 >

嵌入类型具有UnmarshalJSON时json.Unmarshal失败

姜烨伟
2023-03-14
问题内容

我正在尝试解组具有嵌入式类型的结构。当嵌入式类型具有UnmarshalJSON方法时,外部类型的解封将失败:

https://play.golang.org/p/Y_Tt5O8A1Q

package main


import (
    "fmt"

    "encoding/json"
)

type Foo struct {
    EmbeddedStruct
    Field string
}

func (d *Foo) UnmarshalJSON(from []byte) error {
    fmt.Printf("Foo.UnmarshalJSON\n")

    type Alias Foo
    alias := &Alias{}
    if err := json.Unmarshal(from, alias); err != nil {
        return fmt.Errorf("Error in Foo.UnmarshalJSON: json.Unmarshal returned an error:\n%v\n", err)
    }
    *d = Foo(*alias)

    return nil
}

type EmbeddedStruct struct {
    EmbeddedField string
}

func (d *EmbeddedStruct) UnmarshalJSON(from []byte) error {
    fmt.Printf("EmbeddedStruct.UnmarshalJSON\n")

    type Alias EmbeddedStruct
    alias := &Alias{}
    if err := json.Unmarshal(from, alias); err != nil {
        return fmt.Errorf("Error in EmbeddedStruct.UnmarshalJSON: json.Unmarshal returned an error:\n%v\n", err)
    }
    *d = EmbeddedStruct(*alias)

    return nil
}

func main() {

    data := `{"EmbeddedField":"embeddedValue", "Field": "value"}`
    foo := &Foo{}

    json.Unmarshal([]byte(data), foo)

    fmt.Printf("Foo: %v\n", foo)

    if foo.EmbeddedField != "embeddedValue" {
        fmt.Printf("Unmarshal didn't work, EmbeddedField value is %v. Should be 'embeddedValue'\n", foo.EmbeddedField)
    }

    if foo.Field != "value" {
        fmt.Printf("Unmarshal didn't work, Field value is %v. Should be 'value'\n", foo.Field)
    }

}

输出为:

Foo.UnmarshalJSON
EmbeddedStruct.UnmarshalJSON
Foo: &{{embeddedValue} }
Unmarshal didn't work, Field value is . Should be 'value'

…因此两个自定义解组函数都运行了。来自嵌入式结构的值是正确的,但是来自外部结构的值将丢失。

如果我们只是删除EmbeddedStruct.UnmarshalJSON方法,它将按预期工作。

难道我做错了什么?这是预期的吗?还是一个错误?我确定有一种方法可以调整UnmarshalJSON方法以使其正常工作。


问题答案:

可以预料的。

创建别名时:

type Alias Foo

Alias不会继承方法,Foo因为它是具有不同方法集的不同类型,而这是您要避免无限递归而要实现的目标。

然而 ,嵌入EmbeddedStructUnmarshalJSON方法,反而会得到提升!

因此,Alias将有一个UnmarshalJSON仅能解组EmbeddedStruct值的方法,而不是使用所需的默认解组方法。



 类似资料:
  • 问题内容: 为了与大摇大摆进行交互,我需要制作一个自定义结构,该结构只不过是围绕go’s进行包装。 我希望最终会打来电话,会回来。相反,我得到了以下输出: 但是我真正想要的是: 而且我必须添加以下代码来做到这一点: 但是,根据Effective Go的关于嵌入结构的部分 ,这根本没有必要。为什么显示为? 问题答案: 实现自定义JSON marshaler(),请参见。但是此方法具有指针接收器,因此

  • 问题内容: 我想执行一些其他步骤来初始化实现中的数据结构。在该实现内调用自然会导致堆栈溢出。 JSON解码器会不断尝试查找,如果有自定义实现,然后再次调用。 还有另一种方法吗?只是调用基本的默认实现而不会导致此问题? 问题答案: 避免这种情况/避免这种情况发生的一种简单且常见的方法是使用关键字创建一个新类型,并使用类型转换来传递该类型的值(该值可能是您的原始值,因为新的类型具有原始类型作为其基础类

  • 我有一个,它嵌入一个指向另一个的嵌入指针。当我使用默认的行为时,它可以完美地工作。但是,当我为嵌入式的类型而不是为外部实现时,就会出现空指针取消引用的恐慌。 如果我也为外部类型实现,那么它就可以工作了。但是,外部结构有许多字段,我不想手动解封。 为什么在其中一个而不是另一个上实现会导致恐慌? 有没有一种方法可以让它工作而不为外部类型实现? 如果没有,是否有更简单/更少手动的方法来为外部类型实现?

  • 我得到警告,因为警告:失败的道具类型:组件:道具类型是无效的;它必须是一个函数,通常来自包,但收到了 我的代码是: 我的功能运行正常,但出现此控制台错误是否有人可以帮助我解决此警告?

  • 我想要一个函数,该函数可以执行以下操作: 更一般地说,是否存在与此模式匹配的typeclass?

  • 我在许多组件中使用了几个大型对象,因此我为每个大型对象创建了一个proptypes文件,如下所示: 其中包含从"prop类型"导入PropType; 我在组件中使用对象,如下所示: 它给我一个警告,Prop类型“PropLargeObject”无效,它必须是一个函数,通常来自React。道具类型。我做错了什么?