The following code tries to show the address of a method associated to struct.
package main
import (
"fmt"
"reflect"
)
type II interface {
Callme()
}
type Str struct {
I int
S string
}
func (s *Str) Callme () {
fmt.Println("it is me")
}
func main() {
s0 := &Str{}
t := reflect.TypeOf(s0)
v := reflect.ValueOf(s0)
fmt.Println("Callme ", s0.Callme) //real address ?
fmt.Println(t.Method(0).Name, v.Method(0)) //real address ?
s1 := &Str{}
t1 := reflect.TypeOf(s1)
v1 := reflect.ValueOf(s1)
fmt.Println("Callme ", s1.Callme) //real address ?
fmt.Println(t1.Method(0).Name, v1.Method(0)) //real address ?
}
The output is :
Callme 0x4bc2d0
Callme 0x4ab2c0
Callme 0x4bc2d0
Callme 0x4ab2c0
So I have two questions:
First, why these statements do not show identical values ?
fmt.Println("Callme ", s0.Callme)
fmt.Println(t.Method(0).Name, v.Method(0))
Second, why these statements show identical values ?
fmt.Println(t.Method(0).Name, v.Method(0))
fmt.Println(t1.Method(0).Name, v1.Method(0))
The fmt
package calls Value.Pointer to get function addresses.
Let's look at an example of what Value.Pointer
returns for the functions:
s0 := &Str{}
v0 := reflect.ValueOf(s0)
fmt.Printf("s0.Callme: %0x %0x\n", reflect.ValueOf(s0.Callme).Pointer(), s0.Callme)
fmt.Printf("v0.Method(0) %0x %0x\n", v0.Method(0).Pointer(), v0.Method(0))
s1 := &Str{}
v1 := reflect.ValueOf(s1)
fmt.Printf("s1.Callme %x %x\n", reflect.ValueOf(s1.Callme).Pointer(), s1.Callme)
fmt.Printf("v1.Method(0) %x %x\n", v1.Method(0).Pointer(), v1.Method(0))
The output is:
s0.Callme: 105240 105240
v0.Method(0) eee60 eee60
s1.Callme 105240 105240
v1.Method(0) eee60 eee60
This matches the pattern shown in the question.
The function related code for Value.Pointer is:
if v.flag&flagMethod != 0 {
// As the doc comment says, the returned pointer is an
// underlying code pointer but not necessarily enough to
// identify a single function uniquely. All method expressions
// created via reflect have the same underlying code pointer,
// so their Pointers are equal. The function used here must
// match the one used in makeMethodValue.
f := methodValueCall
return **(**uintptr)(unsafe.Pointer(&f))
}
p := v.pointer()
// Non-nil func value points at data block.
// First word of data block is actual code.
if p != nil {
p = *(*unsafe.Pointer)(p)
}
return uintptr(p)
A reflect.Value
created through a method expression in the reflect API has the flagMethod
method bit set. As the comment states and the code shows, the Pointer method returns the same value for all method expressions created this way.
The reflect.Value
created by relect.ValueOf(s1.Callme)
does not have the flagMethod
method bit set. In this case, the function returns the pointer to the actual code.
The output of this program shows all of the combinations:
type StrA struct {
I int
S string
}
func (s *StrA) Callme() {
fmt.Println("it is me")
}
type StrB struct {
I int
S string
}
func (s *StrB) Callme() {
fmt.Println("it is me")
}
s0A := &StrA{}
v0A := reflect.ValueOf(s0A)
s1A := &StrA{}
v1A := reflect.ValueOf(s0A)
fmt.Println("s0A.Callme ", reflect.ValueOf(s0A.Callme).Pointer())
fmt.Println("v0A.Method(0) ", v0A.Method(0).Pointer())
fmt.Println("s1A.Callme ", reflect.ValueOf(s1A.Callme).Pointer())
fmt.Println("v1A.Method(0) ", v1A.Method(0).Pointer())
s0B := &StrB{}
v0B := reflect.ValueOf(s0B)
s1B := &StrB{}
v1B := reflect.ValueOf(s0B)
fmt.Println("s0B.Callme ", reflect.ValueOf(s0B.Callme).Pointer())
fmt.Println("v0B.Method(0) ", v0B.Method(0).Pointer())
fmt.Println("s1B.Callme ", reflect.ValueOf(s1B.Callme).Pointer())
fmt.Println("v1B.Method(0) ", v1B.Method(0).Pointer())
Output:
s0A.Callme 1061824
v0A.Method(0) 978528
s1A.Callme 1061824
v1A.Method(0) 978528
s0B.Callme 1061952
v0B.Method(0) 978528
s1B.Callme 1061952
v1B.Method(0) 978528
We can observe that Value.Pointer returns the same value for all method expressions created through the reflect API. This includes methods on different types.
We can also observe that Value.Pointer
returns the same value for all method expressions on a given type and method. This is true for method expressions bound to different values.
The Value.Pointer documentation says:
If v's Kind is Func, the returned pointer is an underlying code pointer, but not necessarily enough to identify a single function uniquely. The only guarantee is that the result is zero if and only if v is a nil func Value.
Given this, an application cannot reliably use Value.Pointer or printed values through the fmt
package to compare functions and methods.