背景
Go语言中有着面向对象的思想,当我们创建了一个类型之后,可以给这个类型添加不同的方法,给类型添加方法的方式类似于创建一个函数,只是在func和函数名中添加一个(类型名 类型)。这个东西就是所谓的接收者,也就是类型作为接收者接收该函数为自己的方法。有时候我们希望可以更改类型中成员变量的值,而有时候我们不希望类型中成员变量的值被改变。这就是Golang中使用值接收者与指针接收者的区别。
一个例子
语言叙述比较繁琐,直接看这个简单的例子:
package main
import "fmt"
type user struct {
name string
email string
}
func (u user) changeEmail0(NewEmail string) {
u.email = NewEmail
fmt.Println("changeEmail0: userName is ",u.name," userEmail is ",u.email)
}
func (u *user) changeEmail1(NewEmail string) {
u.email = NewEmail
fmt.Println("changeEmail1: userName is ",u.name," userEmail is ",u.email)
}
func main() {
usr0 := &user{"pf", "xxxxxxxxx@qq.com"}
usr0.changeEmail0("xxxxxxxxx@163.com")
fmt.Println("main: userName is ",usr0.name," userEmail is ",usr0.email)
usr1 := &user{"pf", "xxxxxxxxx@qq.com"}
usr1.changeEmail1("xxxxxxxxx@163.com")
fmt.Println("main: userName is ",usr1.name," userEmail is ",usr1.email)
}
这个例子中第10行的func (u user) changeEmail0(NewEmail string)
就是将user类型作为值接收者,在使用值接收者时,方法中使用的类型的值只是一个副本,也就是说,无论怎么更改类型中成员变量的值,都对原值不会有任何影响,仅仅是在方法内部有所改变而已。
15行的func (u *user) changeEmail1(NewEmail string)
是将user类型作为指针接收者,方法中使用的是该类型的原值,也就是说,在方法中改变该值,那么原值也会有所改变。
该代码的结果
changeEmail0: userName is pf userEmail is xxxxxxxxx@163.com
main: userName is pf userEmail is xxxxxxxxx@qq.com
changeEmail1: userName is pf userEmail is xxxxxxxxx@163.com
main: userName is pf userEmail is xxxxxxxxx@163.com
可以看出值接收者与指针接收者的区别。
总结
使用值接收者还是指针接收者,不应该由该方法是否修改了接收到的值来决定。这个决策应该基于该类型的本质。简单来说,如果给这个类型增加或者删除某个值,是需要创建一个新值,则选择值接收者。如果要修改当前的值,则选择指针接收者。