Golang interface to struct

You can't append data arbitrarily to a struct; they're statically typed. You can only assign values to the fields defined for that specific struct type. Your best bet is probably to use a map instead of structs for this.


Adrian is correct. To take it a step further, you can only do anything with interfaces if you know the type that implements that interface. The empty interface, interface{} isn't really an "anything" value like is commonly misunderstood; it is just an interface that is immediately satisfied by all types.

Therefore, you can only get values from it or create a new "interface" with added values by knowing the type satisfying the empty interface before and after the addition.

The closest you can come to doing what you want, given the static typing, is by embedding the before type in the after type, so that everything can still be accessed at the root of the after type. The following illustrates this.

https://play.golang.org/p/JdF7Uevlqp

package main

import (
    "fmt"
)

type Before struct {
    m map[string]string
}

type After struct {
    Before
    s []string
}

func contrivedAfter(b interface{}) interface{} {
    return After{b.(Before), []string{"new value"}}
}

func main() {
    b := Before{map[string]string{"some": "value"}}
    a := contrivedAfter(b).(After)
    fmt.Println(a.m)
    fmt.Println(a.s)
}

Additionally, since the data you are passing to the template does not require you to specify the type, you could use an anonymous struct to accomplish something very similar.

https://play.golang.org/p/3KUfHULR84

package main

import (
    "fmt"
)

type Before struct {
    m map[string]string
}

func contrivedAfter(b interface{}) interface{} {
    return struct{
        Before
        s []string
    }{b.(Before), []string{"new value"}}
}

func main() {
    b := Before{map[string]string{"some": "value"}}
    a := contrivedAfter(b)
    fmt.Println(a)
}

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.