De- и encode interface {} с Gob
Я пытаюсь де- и кодировать структуру, содержащую поле Interface {} as.
Проблема в том, что кодировка работает нормально, но если я попытаюсь декодировать данные до data
, значение получит { <nil>}
.
Это действительно работает, если я изменяю Data interface{}
на Data substring
, но это не решение для меня, потому что я хочу кэшировать результаты запроса в базу данных, которые имеют разные типы в зависимости от запроса. (например, Users
или Cookies
)
Минимальный рабочий пример
Источник
http://play.golang.org/p/aX7MIfqrWl
package main
import (
"bytes"
"encoding/gob"
"fmt"
)
type Data struct {
Name string
Data interface{}
}
type SubType struct {
Foo string
}
func main() {
// Encode
encodeData := Data{
Name: "FooBar",
Data: SubType{Foo: "Test"},
}
mCache := new(bytes.Buffer)
encCache := gob.NewEncoder(mCache)
encCache.Encode(encodeData)
fmt.Printf("Encoded: ")
fmt.Println(mCache.Bytes())
// Decode
var data Data
pCache := bytes.NewBuffer(mCache.Bytes())
decCache := gob.NewDecoder(pCache)
decCache.Decode(&data)
fmt.Printf("Decoded: ")
fmt.Println(data)
}
Результаты
Ожидаемый результат
Закодировано: [37 255 129 3 1 1 4 68 97 116 97 1 255 130 0 1 2 1 4 78 97 109 101 1 12 0 1 4 68 97 116 97 1 255 132 0 0 0 29 255 131 3 1 1 7 83 117 98 84 121 112 101 1 255 132 0 1 1 1 3 70 111 111 1 12 0 0 0 19 255 130 1 6 70 111 111 66 97 114 1 1 4 84 101 115 116 0 0]
Декодировано: {FooBar {Test}}
Текущий результат
Закодировано: [37 255 129 3 1 1 4 68 97 116 97 1 255 130 0 1 2 1 4 78 97 109 101 1 12 0 1 4 68 97 116 97 1 255 132 0 0 0 29 255 131 3 1 1 7 83 117 98 84 121 112 101 1 255 132 0 1 1 1 3 70 111 111 1 12 0 0 0 19 255 130 1 6 70 111 111 66 97 114 1 1 4 84 101 115 116 0 0]
Декодировано: {}
Ответы
Ответ 1
Вы не можете декодировать в интерфейс, потому что декодер не имеет возможности определить, какой тип должно быть полем.
Вы можете справиться с этим несколькими способами. Один из них заключается в том, чтобы Data хранит структуру с полем для каждого типа, который может быть декодирован. Но тип может быть очень сложным.
Другой способ - реализовать интерфейс GobDecoder и GobEncoder для вашей структуры и реализовать собственную сериализацию для типов. Это, вероятно, не идеально, хотя.
Возможно, лучший подход состоит в том, чтобы вместо этого использовать кеш-память определенных типов и использовать отдельный метод для каждого типа. Использовать ваш пример. У вашего приложения будет кеш-метод с именем GetSubType(key string) (*SubType, error)
в кеше. Это приведет к возврату конкретного типа или ошибки декодирования вместо интерфейса. Это было бы более чистым и читаемым, а также более типичным.
Ответ 2
Проблема заключается в том, что в вашем коде есть ошибка при выполнении encCache.Encode(encodeData)
, но поскольку вы не проверяете наличие ошибки, вы этого не понимаете. Выход пуст, потому что encodedData не удается правильно закодировать.
Если вы добавите проверку ошибок,
err := enc.Encode(encodeData)
if err != nil {
log.Fatal("encode error:", err)
}
Затем вы увидите что-то вроде
2013/03/09 17:57:23 encode error:gob: type not registered for interface: main.SubType
Если вы добавите одну строку в исходный код до enc.Encode(encodeData),
gob.Register(SubType{})
Затем вы получите ожидаемый результат.
Decoded: {FooBar {Test}}
См. http://play.golang.org/p/xt4zNyPZ2W