无法反序列化结构(“类型的值不可分配给类型”)

时间:2019-10-31 17:00:48

标签: json go serialization yaml deserialization

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

我尝试使用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)
}

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

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()
}

1 个答案:

答案 0 :(得分:0)

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

要解决此问题,必须在反序列化期间找出Objects中每个单独的数组元素的类型,然后根据该结构进行反序列化。有多种方法可以完成。

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

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,但这将需要大量类型断言。