I have been struggling to understand the difference between encoding/decoding an interface type when that type is embedded in a struct, vs. when it's not embedded at all.
Using the following example: here in the playground
Note the code declares an interface IFace
. It declares a non-exported struct impl
. It sets up a few Gob methods to Register
, GobEncode
, and GobDecode
the impl
struct.
Then, it also declares a struct Data
which is exported, and has a single field Foo
which is of the interface type IFace
.
So, there's an interface, a struct which implements it, and a container struct which has a field whose value is that interface type.
My problem is that the container struct Data
is happily sent through the Gob gauntlet, and, when it goes through, it happily encodes and decodes the IFace field in the Data
struct... great! But, I cannot seem to be able to send just an instance of the IFace value through the gob gauntlet.
What is the magic invocation I am missing?
Searching for the error message gives a number of results, but I believe I have satisfied the Gob contract.... and the "proof" of that is in the successful struct gobbing. Obviously I have missed something, but can't see it.
Note, the output of the program is:
Encoding {IFace:bilbo} now
Encoding IFace:baggins now
Decoded {IFace:bilbo} now
decode error: gob: local interface type *main.IFace can only be decoded from remote interface type; received concrete type impl
Decoded <nil> now
The actual code is:
package main
import (
"bytes"
"encoding/gob"
"fmt"
)
type IFace interface {
FooBar() string
}
type impl struct {
value string
}
func init() {
gob.Register(impl{})
}
func (i impl) FooBar() string {
return i.value
}
func (i impl) String() string {
return "IFace:" + i.value
}
func (i impl) GobEncode() ([]byte, error) {
return []byte(i.value), nil
}
func (i *impl) GobDecode(dat []byte) error {
val := string(dat)
i.value = val
return nil
}
func newIFace(val string) IFace {
return impl{val}
}
type Data struct {
Foo IFace
}
func main() {
var network bytes.Buffer // Stand-in for a network connection
enc := gob.NewEncoder(&network) // Will write to network.
dec := gob.NewDecoder(&network) // Will read from network.
var err error
var bilbo IFace
bilbo = newIFace("bilbo")
var baggins IFace
baggins = newIFace("baggins")
dat := Data{bilbo}
fmt.Printf("Encoding %v now\n", dat)
err = enc.Encode(dat)
if err != nil {
fmt.Println("encode error:", err)
}
fmt.Printf("Encoding %v now\n", baggins)
err = enc.Encode(baggins)
if err != nil {
fmt.Println("encode error:", err)
}
var pdat Data
err = dec.Decode(&pdat)
if err != nil {
fmt.Println("decode error:", err)
}
fmt.Printf("Decoded %v now\n", pdat)
var pbag IFace
err = dec.Decode(&pbag)
if err != nil {
fmt.Println("decode error:", err)
}
fmt.Printf("Decoded %v now\n", pbag)
}
encoding/json
. Is there an equivalent forencoding/gob
? – Brutifythe reflector knows the underlying type
problem. change interface to struct, and embed the dynamic types in that struct. – Shellieshellproof