GoB Panics декодирования интерфейса
У меня есть структура с неэкспортированными полями, которые должны кодироваться и декодироваться.
Сказать:
type A struct {
s int
}
func (a *A) Inc() {
a.s++
}
Очевидно, что в этом случае мне нужно реализовать gob.GobEncoder
а также gob.GobDecoder
интерфейсы. И если я использую структуру напрямую, все работает нормально:
https://play.golang.org/p/dm3HwaI8eU
Но мне также нужно иметь интерфейс, который реализует ту же логику и является сериализуемым:
type Incer interface {
gob.GobEncoder
gob.GobDecoder
Inc()
}
Полный код: https://play.golang.org/p/Zig2mPrnrq
И вдруг паникует
panic: interface conversion: interface is nil, not gob.GobDecoder [recovered]
panic: interface conversion: interface is nil, not gob.GobDecoder
Но если я прокомментирую интерфейсы gob, все снова станет хорошо.
Я что-то упустил? Потому что описанное поведение кажется мне довольно странным
2 ответа
Проблема заключается в том, что Incer
Интерфейс реализует специальный интерфейс, особенный для encoding/gob
пакет: gob.GobDecoder
,
Если твой Incer
интерфейс содержит только Inc()
метод, он будет работать, потому что декодер gob видит, что вы декодируете в тип интерфейса, и будет использовать переданный тип для декодирования значения и проверки во время выполнения, реализует ли декодированное значение (тип которого включен и передается в потоке) тип интерфейса назначения, и в этом случае он будет:
type Incer interface {
Inc()
}
Так что расшифровка удалась.
Если Incer
Интерфейс также встраивает gob.GobEncoder
а также gob.GobDecoder
интерфейсы, они по определению ответственны за кодирование / декодирование. Если тип реализует эти интерфейсы, декодер не будет пытаться декодировать значение, используя переданный тип, а вместо этого вызовет GobDecode()
метод целевого значения, при необходимости создающий нулевое значение.
Так как вы проходите nil
значение для Decoder.Decode()
декодер должен создать нулевое значение, но он не знает, какой тип создать, поскольку передаваемое вами значение является указателем на интерфейс. Вы не можете создать значение типа интерфейса, только значение конкретного типа, которое может удовлетворять определенным интерфейсам.
Вы не можете включить gob.GobEncoder
а также gob.GobDecoder
в вашем Incer
интерфейс. Я знаю, что вы хотите убедиться, что реализации действительно их реализуют, но тогда - как вы можете видеть - вы не сможете декодировать их в "общий" Incer
значение интерфейса Кроме того, я даже не вижу необходимости включать их в Incer
: gob.GobEncoder
а также gob.GobDecoder
не единственные способы сделать их передаваемыми, есть также encoding.BinaryMarshaler
а также encoding.BinaryUnmarshaler
которые проверены encoding/gob
пакет.
В вашем случае вам нужно определить, какой "макет" памяти вы ожидаете, декодирование сбрасывает в значение вашего интерфейса. Когда вы объявляете
var v Incer
Вы не даете подсказке декодеру о том, как должно быть выполнено декодирование. если вы говорите декодеру, что ожидаете декодировать структуру main.A, она может использовать методы (*A).GobEncode() и (*A).GobDecode(), которые вы определили:
var v Incer
v = &A{}
Ссылка на игровую площадку: https://play.golang.org/p/WUNRKGTVIS