Golang的值接收者与指针接收者

背景

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

可以看出值接收者与指针接收者的区别。

总结

使用值接收者还是指针接收者,不应该由该方法是否修改了接收到的值来决定。这个决策应该基于该类型的本质。简单来说,如果给这个类型增加或者删除某个值,是需要创建一个新值,则选择值接收者。如果要修改当前的值,则选择指针接收者。

发表评论

电子邮件地址不会被公开。 必填项已用*标注