Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Golang interface to struct

I have a function that has a parameter with the type interface{}, something like:

func LoadTemplate(templateData interface{}) {

In my case, templateData is a struct, but each time it has a different structure. I used the type "interface{}" because it allows me to send all kind of data.

I'm using this templateData to send the data to the template:

err := tmpl.ExecuteTemplate(w, baseTemplateName, templateData)

But now I want to append some new data and I don't know how to do it because the "interface" type doesn't allow me to add/append anything.

I tried to convert the interface to a struct, but I don't know how to append data to a struct with an unknown structure.

If I use the following function I can see the interface's data:

templateData = appendAssetsToTemplateData(templateData)

func appendAssetsToTemplateData(t interface{}) interface{} {
    switch reflect.TypeOf(t).Kind() {
    case reflect.Struct:
        fmt.Println("struct")
        s := reflect.ValueOf(t)
        fmt.Println(s)

        //create a new struct based on current interface data
    }

    return t
}

Any idea how can I append a child to the initial interface parameter (templateData)? Or how can I transform it to a struct or something else in order to append the new child/data?

like image 243
Pascut Avatar asked Jun 28 '17 14:06

Pascut


1 Answers

Not recommended, but you can create structs dynamically using the reflect package.

Here is an example:

package main

import (
    "encoding/json"
    "os"
    "reflect"
)

type S struct {
    Name string
}

type D struct {
    Pants bool
}

func main() {
    a := Combine(&S{"Bob"}, &D{true})
    json.NewEncoder(os.Stderr).Encode(a)
}

func Combine(v ...interface{}) interface{} {
    f := make([]reflect.StructField, len(v))
    for i, u := range v {
        f[i].Type = reflect.TypeOf(u)
        f[i].Anonymous = true
    }

    r := reflect.New(reflect.StructOf(f)).Elem()
    for i, u := range v {
        r.Field(i).Set(reflect.ValueOf(u))
    }
    return r.Addr().Interface()
}

You could use something like the Combine function above to shmush any number of structs together. Unfortunately, from the documentation:

StructOf currently does not generate wrapper methods for embedded fields. This limitation may be lifted in a future version.

So your created struct won't inherit methods from the embedded types. Still, maybe it does what you need.

like image 86
chowey Avatar answered Oct 06 '22 00:10

chowey