Пакет fmt
вызывает Value.Pointer для получения адресов функций.
Давайте рассмотрим пример того, что Value.Pointer
возвращает для функций:
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))
Вывод:
s0.Callme: 105240 105240
v0.Method(0) eee60 eee60
s1.Callme 105240 105240
v1.Method(0) eee60 eee60
Это соответствует схеме, показанной в вопросе.
Код, связанный с функцией для Value.Pointer :
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
, созданный с помощью выражения метода в отражающем APIустановлен бит метода flagMethod
.Как говорится в комментарии, и код показывает, что метод Pointer возвращает одинаковое значение для всех выражений метода, созданных таким образом.
reflect.Value
, созданный relect.ValueOf(s1.Callme)
, не имеет установленного бита метода flagMethod
.В этом случае функция возвращает указатель на фактический код.
Вывод этой программы показывает все комбинации:
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())
Вывод:
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
Мы можем заметить, что Value.Pointer возвращает одинаковое значение для всех выражений метода , созданных через отражающий API.Это включает методы разных типов.
Мы также можем заметить, что Value.Pointer
возвращает одинаковое значение для всех выражений метода для данного типа и метода.Это верно для выражений метода, связанных с различными значениями.
Документация Value.Pointer говорит:
Если v для Kind - Func, возвращаемый указатель - этоуказатель на основной код, но не обязательно достаточный для уникальной идентификации одной функции.Единственная гарантия состоит в том, что результат равен нулю тогда и только тогда, когда v является значением nil func.
При этом приложение не может надежно использовать Value.Pointer или печатать значения через пакет fmt
длясравнить функции и методы.