I was tinkering with reflection in Go, and I came across an interesting scenario. call1()
works (returns "hello!"
) while call2()
panics with reflect: Call using interface {} as type string
.
In the code below, the only difference between call1()
and call2()
is how inValue
is created and initialized. I can see clearly why call1()
results in inValue
being a string
, while call2()
results in inValue
being an interface
, so my question is not so much as to why my code produces this, but rather:
Why can't Go perform the function call in the second case? I thought the interface still contains all the necessary information for calling the method successfully, given that xCopy
is still really representing a string underneath. (Yes, I did already read the laws of reflection)
I'll note that due to what I'm working on, I do need inValue
to be settable within the function (hence the use of pointers).
Thanks!
func main() {
fmt.Println(call1(foo, "hello"))
fmt.Println(call2(foo, "hello"))
}
func foo(x string) string {
return x + "!"
}
func call1(f, x interface{}) interface{} {
fValue := reflect.ValueOf(f)
inValue := reflect.New(reflect.TypeOf(x)).Elem()
inValue.Set(reflect.ValueOf(x))
inValue.Set(fValue.Call([]reflect.Value{inValue})[0])
return inValue.Interface()
}
func call2(f, x interface{}) interface{} {
fValue := reflect.ValueOf(f)
xCopy := x
inValue := reflect.ValueOf(&xCopy).Elem()
inValue.Set(fValue.Call([]reflect.Value{inValue})[0])
return inValue.Interface()
}
Edit
Perhaps the question then becomes: Why doesn't Go assign the real type, rather than interface
, for inValue := reflect.ValueOf(&xCopy).Elem()
?
The panic message explains the problem. The value in reflect.ValueOf(&xCopy)
has type *interface{}
. The Elem()
of this value has type interface{}
. The function argument is of type string
. An interface{}
value is not a string
value, even when the interface{}
contains a string
.
Note that the address of an interface value is a pointer to the interface, not a pointer to the value in the interface.