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。因此,人们提出了一些解决办法——正如围棋设计师们希望我所期待的那样。