user986408
user986408

Reputation:

How I can write a single function to work with different types

Given the following example, is it anyhow possible to create a function that can literally reproduce (not only get the reflect.Type) the actual type for further manipulation? I know go is statically typed and although it's very cool that I can pass any struct to a function that defines an interface parameter, is there any chance I can do more the other way around?

I already looked into the reflect package but only found stuff that returned a reflect.Type or reflect.Value. I used the New() method which returned a new reflect.Value - and there I couldn't set any fields. Maybe someone experienced with the reflect package can tell me if this is definitely possible or not - or if there's another way to do it.

package main

import "fmt"

type User struct {
    Name string
}

func main() {
    user := User{Name:"FooBar"}
    DoSomethingGenericWithStruct(user)
}

func DoSomethingGenericWithStruct(i interface{}) {
    // access fields of i ...
    // or create slice of type of i ([]User) ...
    // or instantiate new object of type of i (new User) ...
    // ...
}

Upvotes: 1

Views: 100

Answers (1)

OneOfOne
OneOfOne

Reputation: 99244

You would have to pass a pointer to your struct to be able to modify it.

Also keep in mind that using reflection has a high runtime performance cost.

func DoSomethingGenericWithStruct(i interface{}) {
    val := reflect.ValueOf(i)
    if val.Kind() != reflect.Ptr {
        panic("need a pointer")
    }
    val = val.Elem() // now you can modify it
    // add error checking and such, this will panic if it's not a struct or there's no "Name" field
    val.FieldByName("Name").SetString("stuff")
}

playground

To create a new element and assign it:

val = val.Elem()
nval := reflect.New(val.Type()).Elem() // create a new struct of the same type
nval.FieldByName("Name").SetString("stuff") 
val.Set(nval)

to modify the actual struct, not reflect.Value, you will have to get the interface{} to it then assert it to your type, for example:

nval := reflect.New(val.Type()).Elem() // create a new struct of the same type
user := nval.Interface().(User)
user.Name = "Stuff"
val.Set(reflect.ValueOf(user))

Upvotes: 1

Related Questions