Unmarshal to Interface Type
In Go, marshaling and unmarshaling data involves converting between in-memory representations and a serialized format. While it's straightforward to marshal data from interface types, unmarshaling to interface types can pose a challenge.
Explanation
Unmarshaling involves creating a concrete instance of a type to receive the data. However, when unmarshaling to an interface type, the unmarshaller cannot determine the specific type of the concrete object to instantiate.
Solution
To resolve this issue, one approach is to implement the Unmarshaler interface for custom types. By implementing Unmarshaler, you provide a custom way for the unmarshaller to create an instance of the concrete type and populate its fields.
type MyType struct { // ... fields } func (m *MyType) Unmarshal(data []byte) error { // Unmarshal the data into the fields of MyType return nil }
This custom unmarshaling method can then be used to unmarshal JSON data into instances of MyType.
Alternatively, you can annotate your type with typeinfo to specify the exact type to unmarshal to.
{"Type": "YourTypeName", ...}
Example
Consider the following modified code:
package main import ( "encoding/json" "fmt" "log" "net" "net/rpc" "net/rpc/jsonrpc" "reflect" "time" ) type Foo interface { SayHello() error } type fakeFoo struct { internalValue string } // Implement Unmarshaler interface for fakeFoo func (f *fakeFoo) Unmarshal(data []byte) error { log.Println("Unmarshaling fakeFoo...") type tmpType fakeFoo return json.Unmarshal(data, (*tmpType)(f)) } func NewFakeFoo() *fakeFoo { f := &fakeFoo{} f.internalValue = "123456789012347" return f } func (m *fakeFoo) SayHello() error { return nil } type FooManager struct { availableFoos []Foo } func NewFooManager() *FooManager { p := new(FooManager) p.availableFoos = make([]Foo, 0) return p } func AddFoo(mm *FooManager, m Foo) { mm.availableFoos = append(mm.availableFoos, m) log.Println("Added type ", reflect.TypeOf(m)) } func (mm *FooManager) GetAvailableFoos(in []Foo, out *[]Foo) error { *out = append(in, mm.availableFoos...) return nil } func startServer(mm *FooManager) { server := rpc.NewServer() server.Register(mm) l, e := net.Listen("tcp", ":8222") if e != nil { log.Fatal("listen error:", e) } for { conn, err := l.Accept() log.Println("Incoming!") if err != nil { log.Fatal(err) } go server.ServeCodec(jsonrpc.NewServerCodec(conn)) } } func main() { fake1 := NewFakeFoo() fooHolder := NewFooManager() AddFoo(fooHolder, fake1) go startServer(fooHolder) time.Sleep(1 * time.Second) // Sleep to allow server to start log.Println("Using standard function call") var foos []Foo fooHolder.GetAvailableFoos(foos, &foos) log.Println(foos) log.Println("Using RPC call") conn, err := net.Dial("tcp", "localhost:8222") if err != nil { log.Fatalln(err) } defer conn.Close() c := jsonrpc.NewClient(conn) err = c.Call("FooManager.GetAvailableFoos", foos, &foos) if err != nil { log.Fatal("GetAvailableFoos error:", err) } log.Println("Success: ", foos) }
When you run this modified code, you'll see successful unmarshaling of interface types over an RPC connection.
The above is the detailed content of How Can I Effectively Unmarshal Data to Interface Types in Go?. For more information, please follow other related articles on the PHP Chinese website!