golang函数方法的接收者有两种:值接收者与指针接收者。
平时使用中两种类型的主要区别就是能不能修改调用者的内部值。
先说结论:值接收者方法不能修改调用者内部的值,指针接收者方法可以修改调用者内部的值。
做个测试:
type Student struct {
age int
}
func (s Student) SetAge(age int) {
s.age = age
}
func (s *Student) SetAge2(age int) {
s.age = age
}
func main() {
st1 := Student{}
st2 := &Student{}
st1.SetAge(11)
fmt.Println("st11:", st1)
st1.SetAge2(12)
fmt.Println("st12:", st1)
st2.SetAge(21)
fmt.Println("st21:", st2)
st2.SetAge2(22)
fmt.Println("st22:", st2)
}
type Student struct {
age int
}
func (s Student) SetAge(age int) {
s.age = age
}
func (s *Student) SetAge2(age int) {
s.age = age
}
func main() {
st1 := Student{}
st2 := &Student{}
st1.SetAge(11)
fmt.Println("st11:", st1)
st1.SetAge2(12)
fmt.Println("st12:", st1)
st2.SetAge(21)
fmt.Println("st21:", st2)
st2.SetAge2(22)
fmt.Println("st22:", st2)
}
输出结果:
st11: {0}
st12: {12}
st21: &{0}
st22: &{22}
可以看出,不论调用者是值还是指针,对于指针接收者方法和值接收者方法,都可以调用。而且指针接收者方法是可以修改调用者(结构体)的内部值,值接收者方法则不行。
虽然在平时使用时,调用者不论是值类型还是指针类型,调用值接收者方法和指针接收者方法都没有问题,但是在涉及到实现接口方法时,有时会遇到如下报错:
Son does not implement Father (SomeFunction method has pointer receiver)
比如:
type Person interface {
SetAge(age int)
SetAge2(age int)
}
type Student struct {
age int
}
func (s Student) SetAge(age int) {
s.age = age
}
func (s *Student) SetAge2(age int) {
s.age = age
}
func main() {
var st1 Person = Student{}
var st2 Person = &Student{}
st1.SetAge(11)
fmt.Println("st11:", st1)
st1.SetAge2(12)
fmt.Println("st12:", st1)
st2.SetAge(21)
fmt.Println("st21:", st2)
st2.SetAge2(22)
fmt.Println("st22:", st2)
}
编译直接报错了:
cannot use Student{} (value of type Student) as type Person in variable declaration:
Student does not implement Person (SetAge2 method has pointer receiver)
意思是Student{}没有实现Person的接口,后面括号指出是SetAge2接口没有实现。
先说结论:*T类型包含了*T和T为接收者的方法,但T类型只包含接收者为T的方法。 (参考:go.dev/doc/faq#Fun…
即,上面的例子中,值类型st1只包含了值类型接收者方法(即SetAge方法),而不包含指针类型接收者方法(即SetAge2方法)。所以,st1这个值类型结构体没有能够完全实现Person接口。
而在前一篇文章的使用例子中,值或者指针调用者之所以可以直接调用不同接收者类型的方法,完全是编译器帮忙做了一些工作:我们的值类型调用者在调用指针类型接收者的方法的时候,会对调用者取址处理来调用其方法,即&st1.SetAge2()。所以,这个调用者能不能调用指针接收者类型的方法,取决于调用者能不能被寻址。而接口的动态值,就是一种不能被寻址的类型。
其他的不能寻址的类型,比如常量:
type Pi int
func (p *Pi) SetValue(age int) {
*p = Pi(age)
}
func (p Pi) SetValue2(age int) {
p = Pi(age)
}
func main() {
const pi Pi = 123
pi.SetValue(1) // 编译报错:cannot call pointer method SetValue on Pi
pi.SetValue2(2) // ok
var pi2 Pi = 3
pi2.SetValue(3) // ok
pi2.SetValue2(4) // ok
}
【迁移】www.cnblogs.com/zxq89/p/177… posted @ 2023-10-15 23:59