Unmarshal into an array of structures defined at runtime in Go

I am trying to dynamically create a slice of structures that I can combine my data, but doing it at runtime based on an unknown type of structure. I do this because I want to have one common bit of code that can unleash anything that implements a particular interface.

eg. (pseudo code)

func unmarshalMyData(myInterface MyInterface, jsonData []byte) { targetSlice := myInterface.EmptySlice() json.Unmarshal(jsonData, &targetSlice) } 

I tried several different alternatives. The most promising is the use of the reflect package to create a slice. Unfortunately, after disassembling, a dynamically created slice has the type []interface{} . If I print the type of dynamically created slice before canceling it, it prints []*main.myObj . Can anyone explain why? See Link to the playground: https://play.golang.org/p/vvf1leuQeY

Is there any other way to dynamically create a slice of structures that correctly cancels?

I know json.RawMessage , but there are several reasons why I cannot use it ... there is no type field in my json. In addition, the code in which I am unmarshalling does not have time to compile the structure, that it is unmarshalling. He only knows that a structure implements a specific interface.

Some code that puzzles me why a dynamically created slice does not retain its type after parsing:

 package main import ( "encoding/json" "fmt" "reflect" ) func main() { input := `[{"myField":"one"},{"myField":"two"}]` myObjSlice := []*myObj{} fmt.Printf("Type of myObjSlice before unmarshalling %T\n", myObjSlice) err := json.Unmarshal([]byte(input), &myObjSlice) if err != nil { panic(err) } fmt.Printf("Type of myObjSlice after unmarshalling %T\n", myObjSlice) myConstructedObjSlice := reflect.MakeSlice(reflect.SliceOf(reflect.TypeOf(&myObj{})), 0, 0).Interface() fmt.Printf("Type of myConstructedObjSlice before unmarshalling %T\n", myConstructedObjSlice) err = json.Unmarshal([]byte(input), &myConstructedObjSlice) if err != nil { panic(err) } fmt.Printf("Type of myConstructedObjSlice after unmarshalling %T\n", myConstructedObjSlice) } type myObj struct { myField string } 

Output:

 Type of myObjSlice before unmarshalling []*main.myObj Type of myObjSlice after unmarshalling []*main.myObj Type of myConstructedObjSlice before unmarshalling []*main.myObj Type of myConstructedObjSlice after unmarshalling []interface {} 
+3
source share
1 answer

You create []*myObj using reflection, but then pass *interface{} to json.Unmarshal . The json package sees the target of the pointer as an interface{} type, and therefore uses its default types to cancel them. You need to create a pointer to the type of slice you are creating, so calling the Interface() method returns exactly the type you want to decouple, and that is *[]*myObj .

 sliceType := reflect.SliceOf(reflect.TypeOf(&myObj{})) slicePtr := reflect.New(sliceType) err = json.Unmarshal([]byte(input), slicePtr.Interface()) 
+5
source

All Articles