golang reflect获取闭包函数指针
请检查代码golang reflect获取闭包函数指针,go,Go,请检查代码 package main import ( "fmt" "reflect" ) func main() { factory := func (name string) func(){ return func (){ fmt.Println(name) } } f1 := factory("f1") f2 := factory("f2") pf1 := reflect.
package main
import (
"fmt"
"reflect"
)
func main() {
factory := func (name string) func(){
return func (){
fmt.Println(name)
}
}
f1 := factory("f1")
f2 := factory("f2")
pf1 := reflect.ValueOf(f1)
pf2 := reflect.ValueOf(f2)
fmt.Println(pf1.Pointer(), pf2.Pointer())
fmt.Println(pf1.Pointer() == pf2.Pointer())
f1()
f2()
}
结果是:
4199328 4199328
true
f1
f2
为什么要使用相同的闭包函数地址呢!
或如何获取唯一地址!
如果v的种类是Func,则返回的指针是底层代码
指针,但不一定足以标识单个函数
独特地唯一的保证是当且仅当
v是一个nil func值
函数指针表示函数的代码。由function literal创建的匿名函数的代码在内存中只存储一次,而不管返回匿名函数值的代码运行多少次。这意味着所有函数值(或者更准确地说是函数指针)都是相同的 因此,您无法区分存储在
f1
和f2
中的值:它们表示调用时要执行的相同代码块
存储在工厂
变量中的函数值返回的函数值是闭包。只要可以访问,它所引用的环境(局部变量和函数参数)就会一直存在。在您的例子中,这意味着由于f1
和f2
中的函数值引用了封闭匿名函数的name
参数,因此只要函数值(在f1
和f2
中)可访问,它们(“它们”来自多个调用)就会被保留。这是唯一使他们“不同”或独特的东西,但这是从“外部”看不见的
如果您继续在闭包中打印name
的地址,您会看到它们对于闭包的多个值是不同的变量,但是如果再次调用相同的闭包(函数值),则是相同的。首先修改闭包以同时打印名称的地址
:
factory := func(name string) func() {
return func() {
fmt.Println(name, &name)
}
}
并多次调用f1
和f2
:
f1()
f2()
f1()
f2()
输出:
f1 0x1040a120
f2 0x1040a130
f1 0x1040a120
f2 0x1040a130
正如您所看到的,如果再次调用相同的闭包,name
参数将被保留,并且相同的name
参数将被再次使用。实际上,Golang中的*func()
类型相当于C中的void(*)(void)
类型(我知道这一点,因为我经常使用cgo)
Go中的func()
被定义为一个文本,这意味着它类似于一个表示机器代码的字节块,而不是一个函数指针
请注意,在Golang中,所有内容都是通过值传递的,甚至Go中的函数也不例外
var f1 func() = ...
reflect.ValueOf(f1)
当您这样做时,我认为您试图获取名为f1
的代码块的前8个字节,而这不是该函数的地址
在Go中,您永远无法获得func()
的地址
因为
func()
是文本,而文本没有地址。文字在内存中不存在。所以你找不到地址。这个问题和答案非常有趣。我发现了一个类似的问题(虽然不是关于闭包),答案很有启发性。Go的设计师们似乎不想进行函数或闭包的比较——即使是使用reflect。因此,人们提出了一些解决办法——正如围棋设计师们希望我所期待的那样。