首先回顾一下Go语言值类型和指针类型直接调用其值接收者方法和指针接收者方法的区别:
先看一个实例:
package main
import "fmt"
type I interface {
Get() int
Set(int)
}
type S struct {
Age int
}
func(s S) Get()int {
return s.Age
}
func(s *S) Set(age int) {
s.Age = age
}
func main() {
s1 := S{}
fmt.Printf("s1:%d\n",s1.Get())
s1.Set(20)
fmt.Printf("s1:%d\n",s1.Get())
s2 := &S{}
fmt.Printf("s2:%d\n",s2.Get())
s2.Set(20)
fmt.Printf("s2:%d\n",s2.Get())
}
上面例子输出:
之所以值类型变量和指针类型变量都可以调用其值接收者方法和指针接收者方法,仅仅是Go语言的语法糖在起作用。
值接收者声明的方法,调用时会使用这个值的一个副本去执行,而指针接收者在调用者会共享调用方法时接收者所指向的值,即可以修改指向的值。
接下来我们主要说明值接收者和指针接收者赋值给接口的区别:
先看一个实例:
package main
import "fmt"
type I interface {
Get() int
Set(int)
}
type S struct {
Age int
}
func(s S) Get()int {
return s.Age
}
func(s *S) Set(age int) {
s.Age = age
}
func main() {
var s I = &S{}
fmt.Printf("%d\n",s.Get())
s.Set(20)
fmt.Printf("%d\n",s.Get())
}
上面例子输出:
但是把23行改为:
var s I = S{}
编译将报错:
大致意思就是:S没有实现Set函数,就没有实现接口I,所以不能赋值。
表面上看*S也没有实现Get函数,但是*S所指向的值实现了Get函数,所以*S也自动拥有Get函数,所以实现接口I。S作为值接收者,Go无从知道值的原始值是什么,因为 值接收者 是份拷贝,所以不能影响S。go 会把指针进行隐式转换得到 value,但反过来则不行。
所以,类型 T
变量只有接受者是 T
的方法;而类型 *T变量
拥有接受者是 T
和 *T
的方法,换句话,当实现了一个接收者是值类型的方法,就可以自动生成一个接收者是对应指针类型的方法,因为两者都不会影响接收者。但是,当实现了一个接收者是指针类型的方法,如果此时自动生成一个接收者是值类型的方法,原本期望对接收者的改变(通过指针实现),现在无法实现,因为值类型会产生一个拷贝,不会真正影响调用者。