Strange behavior for a pointer of an interface

115 views Asked by At

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.

1

There are 1 answers

1
Cerise Limón On BEST ANSWER

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 and main2 will work as I think you expect if you f change to:

func f(x interface{}) {             // print x's underlying value
    fmt.Println(reflect.ValueOf(x))
}

The argument to f in main3 is a *struct{}. The function f dereferences the pointer (with the call to Elem()) and prints the reflect value for the struct{}.

One point that might be confusing is that reflect.ValueOf(ptr).Elem().Elem().Interface() and reflect.ValueOf(ptr).Elem().Interface() return an interface with the same concrete value.

The expression reflect.ValueOf(ptr).Elem() is the reflect value corresponding to i. The call to Interface() on this value returns an interface with the concrete value in i.

The expression reflect.ValueOf(ptr).Elem().Elem() is the reflect value corresponding to i's concrete value. The call to Interface() on this value returns an interface containing that concrete value.