Golang中方法值的结构是什么
Golang中方法值的结构是什么
type sun struct { }
func ( s sun) one( ) { }
func main( ){
var z sun = sun{ }
var x = z.one
}
那么,变量 x 的值看起来是什么样的?
3 回复
x 将是一个指向函数 one 的指针。
因此,x 可以被调用,正如这个 playground 示例 所示。
在Go语言中,方法值(method value)是一个闭包,它绑定了特定的接收者实例。对于你的代码:
package main
type sun struct{}
func (s sun) one() {}
func main() {
var z sun = sun{}
var x = z.one // x是一个方法值
}
变量 x 的类型是 func(),但其内部结构包含两个部分:
- 接收者值:绑定了具体的
sun实例z - 方法指针:指向
sun.one方法的代码
实际上,编译器会将 z.one 转换为类似这样的形式:
// 编译器生成的近似等价代码
x := func() {
z.one() // 闭包捕获了z
}
你可以通过反射来查看方法值的内部结构:
package main
import (
"fmt"
"reflect"
"unsafe"
)
type sun struct {
id int
}
func (s sun) one() {
fmt.Printf("sun.one called with id=%d\n", s.id)
}
func main() {
z := sun{id: 42}
x := z.one
// 查看类型
fmt.Printf("x的类型: %T\n", x) // 输出: func()
fmt.Printf("x的值: %v\n", x) // 输出函数地址
// 使用方法值
x() // 输出: sun.one called with id=42
// 通过反射查看
v := reflect.ValueOf(x)
fmt.Printf("方法值是否有效: %v\n", v.IsValid())
fmt.Printf("方法值类型: %v\n", v.Type())
// 创建另一个实例
z2 := sun{id: 100}
x2 := z2.one
x2() // 输出: sun.one called with id=100
// 比较两个方法值
fmt.Printf("x == x2: %v\n",
reflect.ValueOf(x).Pointer() == reflect.ValueOf(x2).Pointer())
}
输出示例:
x的类型: func()
x的值: 0x1091420
sun.one called with id=42
方法值是否有效: true
方法值类型: func()
sun.one called with id=100
x == x2: false
关键点:
- 每个方法值都是独立的闭包,即使方法相同,绑定的接收者不同也会创建不同的闭包
- 方法值的大小通常为2个机器字(在64位系统上为16字节):一个指向接收者的指针,一个指向方法代码的指针
- 方法值可以像普通函数一样调用,调用时会自动传递绑定的接收者
对于指针接收者的方法,方法值会捕获接收者的指针:
func (s *sun) two() {
fmt.Printf("sun.two called with id=%d\n", s.id)
}
func main() {
z := &sun{id: 42}
y := z.two // y绑定了指向z的指针
z.id = 100
y() // 输出: sun.two called with id=100
}
方法值的这种实现方式使得Go语言的方法调用具有很好的灵活性,可以像函数值一样传递和存储。

