方法调用
方法的接收者有两种:值接收者、指针接收者。这两种有什么区别呢?
来看下面这段代码,最后结果是什么呢?编译错误?
package main
import "fmt"
type Person struct {
age int
}
func (p Person) howOld() int {
return p.age
}
func (p *Person) growUp() {
p.age += 1
}
func main() {
// zhangsan 是值类型
zhangsan := Person{age: 18}
// 值类型 调用接收者也是值类型的方法
fmt.Println(zhangsan.howOld())
// 值类型 调用接收者是指针类型的方法
zhangsan.growUp()
fmt.Println(zhangsan.howOld())
// ----------------------
// stefno 是指针类型
stefno := &Person{age: 100}
// 指针类型 调用接收者是值类型的方法
fmt.Println(stefno.howOld())
// 指针类型 调用接收者也是指针类型的方法
stefno.growUp()
fmt.Println(stefno.howOld())
}
上面输出
18
19
100
101
结论
| 值接收者 | 指针接收者 | |
|---|---|---|
| 值类型调用者 | 方法会使用调用者的一个副本,类似于“传值” | 使用值的引用来调用方法,上例中,qcrao.growUp() 实际上是 (&qcrao).growUp() |
| 指针类型调用者 | 指针被解引用为值,上例中,stefno.howOld() 实际上是 (*stefno).howOld() | 实际上也是“传值”,方法里的操作会影响到调用者,类似于指针传参,拷贝了一份指针 |
接口实现
package main
import "fmt"
type coder interface {
code()
debug()
}
type Gopher struct {
language string
}
func (p Gopher) code() {
fmt.Printf("I am coding %s language\n", p.language)
}
func (p *Gopher) debug() {
fmt.Printf("I am debuging %s language\n", p.language)
}
func main() {
var c coder = &Gopher{"Go"}
c.code()
c.debug()
}
coder 是一个接口类型,定义了 code() 和 debug() 两个函数
一个 Gopher 结构体实现了上面两个方法,注意一个是值接收者,一个是指针接收者
运行下,看结果:
I am coding Go language
I am debuging Go language
把调用者改为值调用者会怎么样呢
func main() {
var c coder = Gopher{"Go"}
c.code()
c.debug()
}
运行下,报错:
src/main.go:23:6: cannot use Gopher literal (type Gopher) as type coder in assignment:
Gopher does not implement coder (debug method has pointer receiver)
第一次是将 &Gopher 赋给了 coder;第二次则是将 Gopher 赋给了 coder。
第二次报错是说,Gopher 没有实现 debug 方法。有的同学可能会问 Gopher 不是可以调用 debug 方法吗,有实现呀。这里犯了一个理解上的错误,Gopher 可以调用 debug 方法是因为 Go 的语法糖。又有同学可能会问,那 *Gopher 也没有实现 code 方法,为什么可以将 &Gopher 赋给 coder。表面上看, *Gopher 类型也没有实现 code 方法,但是因为 Gopher 类型实现了 code 方法,所以让 *Gopher 类型自动拥有了 code 方法。
终于搞清楚了。

本文探讨了Go语言中方法调用的区别,特别是值接收者与指针接收者。通过示例代码展示了接口实现时可能出现的问题,解释了为何*Gopher类型可以拥有Gopher类型实现的方法,而Gopher本身不被认为实现了接口中的所有方法。

被折叠的 条评论
为什么被折叠?



