一、function value
在golang中,函数是一等公民,将函数作为参数、变量或返回值的情况称为function value
。function value
本质上是一个指针,指向runtime.funcval
,这个runtime.funcval
结构体里只有一个地址,即函数指令的入口地址
funcval的struct定义如下
1 | type funcval struct { |
二、无捕获列表的function value
对于无捕获列表的function value
,如果多个变量关联到同一个函数,编译器会做出优化,让它们共用一个funcval
结构体
1 | func simpleFunc() { |
需要注意的是f1,f2不是并不是指向函数的指针,而是指向函数指针的指针,即是一个二级指针,所以在进行强制转换时,要使用 *(**funcval)(unsafe.Pointer(&f1))
的形式
从输出中可以看出f1,f2是共用了同一个funcval结构,且funcval
指向的函数指令地址也相同
不直接通过函数入口地址,而是通过一个二级指针指向函数入口地址再调用主要是为了处理闭包的情况
三、闭包函数
闭包函数其实就是有捕获列表的funcval
结构体,funcval
加上偏移量可以找到每个捕获的变量
1 | func closure() func() int64 { |
闭包函数closure中的局部变量c被捕获,closure
函数会在堆上分配一个funcval
结构体,fn执行函数指令地址,捕获列表捕获了变量c。
由输出可得,这次f1和f2对应了两个不同的funcval
结构,但两个funcval
都指向相同的函数指令地址。f1,f2在调用时,会使用各自funcval
结构中的捕获列表