I wrote 3 similar functions to figure out a strange behavior of Go's pointer reflection.
package main
import (
"reflect"
"fmt"
)
var i interface{} = struct {}{} // i is an interface which points to a struct
var ptr *interface{} = &i // ptr is i's pointer
func f(x interface{}) { // print x's underlying value
fmt.Println(reflect.ValueOf(x).Elem())
}
func main1() { // f is asking for interface? OK, I'll use the struct's interface
structValue := reflect.ValueOf(ptr).Elem().Elem().Interface()
f(structValue)
}
func main2() { // Error? Let me try the struct's pointer
structPtr := reflect.ValueOf(ptr).Elem().Interface()
f(structPtr)
}
func main3() { // Why this one could succeed after New() ?
typ := reflect.ValueOf(ptr).Elem().Elem().Type()
newPtr := reflect.New(typ).Elem().Addr().Interface()
f(newPtr)
}
func main() {
//main1() // panic: reflect: call of reflect.Value.Elem on struct Value
//main2() // panic: reflect: call of reflect.Value.Elem on struct Value
main3() // OK. WHY???
}
Only main3 is working, the other 2 would panic. Why? The key difference of 3 is that it creates a New Value.
As to main2, I think ValueOf().Elem().Interface()
has already reconstructed a interface which points at the struct{}{}
, just don't understand why it would fail.
The value returned from reflect.ValueOf holds the concrete value stored in the argument. If the argument is nil, the zero reflect.Value is returned.
To put this another way, the reflect.Value and the interface passed to reflect.Value have the same underlying value.
The functions
main1
andmain2
will work as I think you expect if youf
change to:The argument to
f
inmain3
is a*struct{}
. The functionf
dereferences the pointer (with the call to Elem()) and prints the reflect value for thestruct{}
.One point that might be confusing is that
reflect.ValueOf(ptr).Elem().Elem().Interface()
andreflect.ValueOf(ptr).Elem().Interface()
return an interface with the same concrete value.The expression
reflect.ValueOf(ptr).Elem()
is the reflect value corresponding toi
. The call toInterface()
on this value returns an interface with the concrete value ini
.The expression
reflect.ValueOf(ptr).Elem().Elem()
is the reflect value corresponding toi
's concrete value. The call toInterface()
on this value returns an interface containing that concrete value.