解释方法表达式的打印值
Explain the printed values of method expressions
以下代码尝试显示与结构关联的方法的地址。
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 ?
}
输出为:
Callme 0x4bc2d0
Callme 0x4ab2c0
Callme 0x4bc2d0
Callme 0x4ab2c0
所以我有两个问题:
首先,为什么这些语句不显示相同的值?
fmt.Println("Callme ", s0.Callme)
fmt.Println(t.Method(0).Name, v.Method(0))
其次,为什么这些语句显示相同的值?
fmt.Println(t.Method(0).Name, v.Method(0))
fmt.Println(t1.Method(0).Name, v1.Method(0))
fmt
包调用 Value.Pointer 获取函数地址。
让我们看一个例子,Value.Pointer
returns 的功能:
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
这与问题中显示的模式相符。
function related code for 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)
通过反射 API 中的 method expression 创建的 reflect.Value
设置了 flagMethod
方法位。正如注释状态和代码所示,Pointer 方法 returns 以这种方式创建的所有方法表达式的值相同。
relect.ValueOf(s1.Callme)
创建的 reflect.Value
没有设置 flagMethod
方法位。在这种情况下,函数 returns 指向实际代码的指针。
this program 的输出显示了所有组合:
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 returns 通过反射 API 创建的所有 method expressions 的值相同。这包括不同类型的方法。
我们还可以观察到 Value.Pointer
returns 对于给定类型和方法的所有 method expressions 都是相同的值。这适用于绑定到不同值的方法表达式。
Value.Pointer documentation 说:
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.
鉴于此,应用程序无法可靠地使用 Value.Pointer 或通过 fmt
包打印的值来比较函数和方法。
以下代码尝试显示与结构关联的方法的地址。
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 ?
}
输出为:
Callme 0x4bc2d0
Callme 0x4ab2c0
Callme 0x4bc2d0
Callme 0x4ab2c0
所以我有两个问题:
首先,为什么这些语句不显示相同的值?
fmt.Println("Callme ", s0.Callme) fmt.Println(t.Method(0).Name, v.Method(0))
其次,为什么这些语句显示相同的值?
fmt.Println(t.Method(0).Name, v.Method(0)) fmt.Println(t1.Method(0).Name, v1.Method(0))
fmt
包调用 Value.Pointer 获取函数地址。
让我们看一个例子,Value.Pointer
returns 的功能:
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
这与问题中显示的模式相符。
function related code for 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)
通过反射 API 中的 method expression 创建的 reflect.Value
设置了 flagMethod
方法位。正如注释状态和代码所示,Pointer 方法 returns 以这种方式创建的所有方法表达式的值相同。
relect.ValueOf(s1.Callme)
创建的 reflect.Value
没有设置 flagMethod
方法位。在这种情况下,函数 returns 指向实际代码的指针。
this program 的输出显示了所有组合:
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 returns 通过反射 API 创建的所有 method expressions 的值相同。这包括不同类型的方法。
我们还可以观察到 Value.Pointer
returns 对于给定类型和方法的所有 method expressions 都是相同的值。这适用于绑定到不同值的方法表达式。
Value.Pointer documentation 说:
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.
鉴于此,应用程序无法可靠地使用 Value.Pointer 或通过 fmt
包打印的值来比较函数和方法。