Невозможно десериализовать структуру («значение типа не присваивается типу») - PullRequest
1 голос
/ 31 октября 2019

Я столкнулся с проблемой при попытке десериализации структуры.

Я пытался использовать 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()
}

1 Ответ

0 голосов
/ 31 октября 2019

Это будет работать при сериализации, поскольку во время сериализации каждый элемент массива Objects является структурами. Он не будет работать при десериализации, потому что во время десериализации Objects является пустым массивом интерфейсов. Вы не можете демаршировать интерфейс, только структуру или значение.

Чтобы это исправить, вы должны выяснить тип каждого отдельного элемента массива в Objects во время десериализации, а затем десериализоваться на основеSTRUCT. Это можно сделать несколькими способами.

Один из способов - использовать толстый интерфейс , временную структуру, содержащую все возможные элементы:

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, но для этого потребуется множество утверждений типа.

...