The difference between decoding gob interface in the structure, compared to the original

I tried to understand the difference between encoding / decoding an interface type when this type is embedded in the structure, and not when it is not implemented at all.

Using the following example: here on the playground

Note that the code declares the IFace interface. It declares an impl structure. It sets up several Gob methods for Register , GobEncode and GobDecode structures.

Then it also declares the Data structure that is being exported, and has one Foo field that has the IFace interface IFace .

So, there is an interface, a structure that implements it, and a container structure that has a field whose value is an interface type.

My problem is that the struct Data container is happily sent through the Gob gauntlet, and when it passes, it happily encodes and decodes the IFace field in the Data structure ... great! But it looks like I can't send only an instance of the IFace value via gauntlet.

What magic spell am I missing?

Searching for an error message gives a number of results, but I believe that I have satisfied the Gob contract ... and the "proof" of this in a successful structuring. Obviously, I missed something, but I don’t see it.

Note. Program Output:

 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 

Actual code:

 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) } 
+5
source share
1 answer

Call

 err = enc.Encode(baggins) 

passes the impl value to Encode . It does not pass a value of type IFace . The document http://research.swtch.com/interfaces can be helpful in understanding why this is so. The value is encoded as a specific impl type.

If you want to decode an interface type, you must encode the interface type. One way to do this is to pass a pointer to an interface value:

 err = enc.Encode(&baggins) 

In this call, a *IFace is passed for encoding. After dereferencing the pointer, the encoder sees that this value is an interface type and encodes it as an interface type. Because the gob package does all the necessary dereferencing and indirect handling when converting values, an additional level of indirection when calling Encode does not require an additional level of indirection when decoding.

playground example

+3
source

Source: https://habr.com/ru/post/1241454/


All Articles