对golang结构体的方法集的理解

今天在看Mark Summerfield写的《Go语言程序设计》里面有句话:“一个自定义类型值的方法集则由该类型定义的接收者类型为值类型的方法组成,但是不包括那些接收者类型为指针的方法。但这种限制并不像这里所说的那样,因为如果我们只有一个值,仍然可以调用一个接收者为指针类型的方法,这可以借助Go语言传真的地址的能力实现,前提是该值是可寻址的(即它是一个变量,一个解引用指针,一个数组或者切片项,或者结构体中的一个可寻址字段)”。

老实说,我很难理解这句话,尤其是后面括号里的,然后书中后面给的一个例子就证明了这个说法,可惜没有非常详细的解释,下面我贴出我本地简化版的代码:

func main() {
	sp := StringPair{1, 2}
	fmt.Println("before ex::", sp)
	sp.Exchage()
	fmt.Println("after ex::", sp)
	doExchange(&sp)
	fmt.Println("again ex::", sp)
}

type StringPair struct {
	first, second int
}

func (sp *StringPair) Exchage(){
	sp.first, sp.second = sp.second, sp.first
}

type Exchanger interface {
	Exchage()
}

func doExchange(sps ...Exchanger){
	for _, sp := range sps {
		sp.Exchage()
	}
}

这里定义了一个接口Exchanger,然后StringPair实现了这个接口,但是把接收者设置为了指针类型。在main() 方法里,sp.Exchange() 能工作,说明引言中所说的那样,借助了Go语言传值是可寻址的能力实现的,这里 sp 是一个结构体值类型的变量,是可以寻址的,所以 sp.Exchange() 没问题。而关键的难点就在 doExchange() 方法里了,由于该方法形式参数类型是接口类型,它并不关心实参是值类型还是指针类型。

比较好理解的方式,也是中规中矩的做法是,既然 StringPair 实现的 Exchange() 的接收者是指针类型,那么保险起见还是传变量的引用绝不会错,事实是我run后结果完全符合预期。

下面我将 main() 里面的 doExchange(&sp) 改为 doExchange(sp),也就是传结构体的值类型:


再跑就出现了下面的错误:


我不是很有把握地说我理解了这个问题,但是我尝试着这样去理解:

1, 第13行的 sp.Exhange() 能run 的确是借助了 Go 语言的传真可寻址的方式实现的

2, 第15行 doExchange(sp) 的参数是值类型(这里的 sp 是结构体StringPair的值类型),根据函数调用参数传递是传值的,doExchange 将会对 sp 做一个拷贝(开销比较大,包含该结构体值类型的所有字节码),然后编译器试图从这个实参也就是 sp 的副本里查找 Exchange() 方法,结果自然是找不到了。

不知道我的理解是不是正确,希望哪位大神看到后能指点一下,谢谢!


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值