0

I would like to know how to set a variable using reflection when using an interface{} value, and all kind of structs could be passed to func F(o interface{}). How to change the first value (s.A) to 'hello'?

package main

import (
    "fmt"
    "reflect"
)

type T struct {
    A string
}

func main() {
    F(T{"foo"})
}

func F(o interface{}) {

    t := reflect.ValueOf(&T{"bar"}).Elem()
    s := reflect.ValueOf(&o).Elem()

    // ok
    fmt.Println("struct:   ", t.Field(0).CanSet())

    // panics - how to set s.A?
    fmt.Println("interface:", s.Field(0).CanSet())
}
Klau3
  • 317
  • 1
  • 2
  • 9

1 Answers1

1

See http://play.golang.org/p/F6M5mfMOTY

When you pass the reference value &o, to reflect.ValueOf, Go is interpreting the Elem() as interface{}, not your original type. If you don't pass as a reference, you get a (non-addressable) instance of your type. I am not 100% sure why this is, but you can definitely see the behavior at the play link above.

One approach would be to create a new addressable instance of your type, and then iterate over the value returned by s to set the fields in the new instance and then return it.

dethtron5000
  • 10,363
  • 1
  • 31
  • 32
  • You are right, I should pass a reference to F(), thanks. – Klau3 Apr 18 '14 at 17:42
  • Here's a slightly revised playground program with clearer output: http://play.golang.org/p/oYoG4-kTzL – Rick-777 Apr 19 '14 at 08:35
  • 1
    "If you don't pass as a reference, you get a (non-addressable) instance of your type. I am not 100% sure why this is, but you can definitely see the behavior at the play link above." It's because you can't directly "point to" the internal copy of the value that an interface value holds. You would have to get the internal value out as an rvalue, modify it, and then put it back into the addressable interface value. – newacct Apr 19 '14 at 09:04