【问题标题】:Unable to deserialize struct ("value of type is not assignable to type")无法反序列化结构(“类型的值不可分配给类型”)
【发布时间】:2020-02-27 02:17:05
【问题描述】:

我在尝试反序列化结构时遇到了问题。

我尝试过使用 JSON 和 YAML,重写结构以使用切片而不是映射(认为这是我使用映射的问题),但都无济于事。

下面的结构包含问题,特别是反序列化函数。我用...替换了不相关的代码:

type Collection struct {
    Objects []Object `yaml:"objects,omitempty"`
}

...

func (c *Collection) Serialize() ([]byte, error) {
    return yaml.Marshal(c)
}

func (c *Collection) Deserialize(raw []byte) error {
    return yaml.Unmarshal(raw, c)
}

我的测试序列化一个集合,然后尝试将第一个集合中的原始数据反序列化到第二个集合中。然后它将比较两个集合,但在反序列化过程中会出现问题:

func TestDeserialize(t *testing.T) {
    c := NewCollection()

    // NewRect creates a Rect (inherits from Object)
    c.AddObject(NewRect(10,10,NewPos(0,0))

    c2 := NewCollection()

    v raw, err := c.Serialize()
    if err != nil {
        t.Fatalf("collection 1 failed to serialize: %v", err)
    }

    // deserialize raw 1 into 2
    // this is the call that fails
    err = c2.Deserialize(raw)
    if err != nil {
        t.Fatalf("collection 2 failed to deserialize: %v", err)
    }
}

这是我一直遇到的错误:

panic: reflect.Set: value of type map[interface {}]interface {} is not assignable to type bw.Object [recovered]
    panic: reflect.Set: value of type map[interface {}]interface {} is not assignable to type bw.Object [recovered]
    panic: reflect.Set: value of type map[interface {}]interface {} is not assignable to type bw.Object

编辑: 我忘了包括Object 的定义。 Object是一个很基础的界面:

type Object interface {
    Update()
    Draw()
    Serialize()
    Deserialize()
}

【问题讨论】:

  • Object的定义是什么?
  • @BurakSerdar 添加了对象定义。谢谢。

标签: json go serialization yaml deserialization


【解决方案1】:

这将在您序列化时起作用,因为在序列化期间Objects 数组的每个元素都是结构。反序列化时它不起作用,因为在反序列化期间,Objects 是一个空的接口数组。您不能解组到接口,只能解组到结构或值。

要解决这个问题,您必须在反序列化过程中找出Objects 中每个单独数组元素的类型,然后根据结构进行反序列化。有多种方法可以做到这一点。

一种方法是使用 fat interface,一个包含所有可能项的临时结构:

type unmarshalObject struct {
   Type string `yaml:"type"`
   // All possible fields of all possible implementations
}

type unmarshalCollection struct {
    Objects []unmarshalObject `yaml:"objects,omitempty"`
}

func (c *Collection) Deserialize(raw []byte) error {
    var intermediate unmarshalCollection
    yaml.Unmarshal(raw, &intermediate)
    c.Objects=make([]Object,0)
    for _,object:=range intermediate.Objects {
        switch object.Type {
          case "rect":
             c.Objects=append(c.Objects,Rectangle{X1:object.X1,...})
          case "...":
           ...
        }
    }
    return nil
}

省略错误检查。

同样的方法可以用于map[string]interface{} 而不是unmarshalObject,但这需要大量的类型断言。

【讨论】:

  • 我想答案会是这样的。谢谢你。我确信我可以找到一种更好的方法来编写不需要像这样奇怪的变通方法的界面。
猜你喜欢
  • 2023-01-25
  • 1970-01-01
  • 1970-01-01
  • 2018-12-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-04-02
  • 1970-01-01
相关资源
最近更新 更多