前言
方法接收者是指针类型和值类型的根本区别只需要明确这一点:它们的方法名是不一样的。
方法名
首先我们定义两个结构体类型:
1 | type Man struct{ |
我们分别使用指针接收者和值接收者给他们添加一个Say()方法:
1 | //此方法的全名为(*Man).Say() |
这里虽然它们都是Say()方法,但实际上方法名是不一样的,如果你使用指针接收者,方法的全名为(*Man).Say(), 如果是值类型,则全名Woman.Say()。严格的来说,对于前者,只能使用(*Man)类型来调用Say()方法,后者则是只能使用Woman类型来调用,因为值类型Man并没有Say()方法,同理指针类型*Woman也没有Say()方法。
编译器隐式转换
但是测试发现,Man.say()也能通过编译:
1 | man := Man{} // man是个值类型 |
原因:go的编译器为我们做了一次隐式转换,即将man.say()转换成了(&man).say(),也就是对man做了取地址的操作。
同理,
1 | Woman := &Woman{} //Woman为指针类型 |
对于接口
对于接口类型,编译器并没有再主动为我们做类型转换
首先定义一个接口:
1 | type Talk interface { |
首先我们承认Man和Woman类型都实现了这个接口。但其实,严格的说,因为Man的Say()方法是指针接收者,所以只是指针类型*Man实现了这个接口,值类型Man并没有实现这个接口。同理,因为Woman的say()方法是值类型,所以只是值类型Woman实现了这个接口,指针类型*Woman并没实现这个接口。
如果你把值类型的Man的变量赋值给接口Talk会报错:
1 | //定义个接口变量 |
其他注意
实例代码:main.go
1 | package main |
从输出结果我们看到,调用值类型的方法和调用指针类型的方法是不同的
当你需要修改a的时候要调用 func (p *Person) modify2()
指针类型的方法
如果你调用 func (p Person) modify1()
这样的值类型的方法是修改不成功的,因为调用时使用的是 a 的一个 copy