Golang中方法值的结构是什么

Golang中方法值的结构是什么

type sun struct { }
func ( s sun) one( ) { }
func main( ){
    var z sun = sun{ }
    var x = z.one
}

那么,变量 x 的值看起来是什么样的?

3 回复

z值如何以及在哪里存储

更多关于Golang中方法值的结构是什么的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


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(),但其内部结构包含两个部分:

  1. 接收者值:绑定了具体的 sun 实例 z
  2. 方法指针:指向 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语言的方法调用具有很好的灵活性,可以像函数值一样传递和存储。

回到顶部