vendredi 9 juin 2017

go reflection: get correct struct type of interface

Consider this:

type myStruct struct {
    Foo string `json:"foo"`
}

func main() {
    somelibrary.DoThing(func(thing myStruct) {
        // myStruct should contain unmarshaled JSON
        // provided by somelibrary

        fmt.Printf("%v\n", thing)
    })
}

I'm new to Go, so I fear this might not be idiomatic code. I'd like to implement somelibrary.DoThing so it correctly infers the struct type from the function argument via reflection, if it's possible. Here's what I have:

const jsonData := []byte{`{"foo": "bar"}`}

func DoThing(fn interface{}) {
    // Get first arg of the function
    firstArg := reflect.TypeOf(fn).In(0)
    structPtr := reflect.New(firstArg)

    // Convert to Interface
    // Note that I can't assert this to .(myStruct) type
    instance := structPtr.Elem().Interface()

    // Unmarshal the JSON
    json.Unmarshal(jsonData, &instance)

    // Call the function
    vfn := reflect.ValueOf(fn)
    vfn.Call([]reflect.Value{reflect.ValueOf(instance)})
}

Without knowing the struct type beforehand, json.Unmarshal just assumes that instance is map[string]interface{}, so I get a panic when calling vfn.Call(...):

panic: reflect: Call using map[string]interface {} as type main.myStruct

Is it possible to convert the instance interface into the correct type? In other words, can I do type type assertion by passing a string (or using some reflection method) instead of having the type available to the program as a symbol?





Aucun commentaire:

Enregistrer un commentaire