Golang方法不同类型接收者的区别

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/yjp19871013/article/details/81428565

Golang中对方法和函数进行了区分,函数就是传统意义上的函数,定义方式如下:

func 函数名(参数列表) (返回值列表) {

}

方法在函数的基础上添加了一个接收者,接收者可以是结构体类型的变量或指针,也可以是slice或者map,也就是说,无法将基本类型的变量或指针作为方法的接收者,只有复合类型的变量或指针才可以作为接收者,定义方法的方式如下:

func (接收者) 方法名(参数列表) (返回值列表) {

}

方法的接收者可以是结构体变量或者指针,但是两者有什么区别呢?很简单,变量接收者无法改变接收者的值,而指针接收者可以修改接收者内部的值。下面我们看一个例子。

type Person struct {
	Name string
}

func (p *Person) PrintMe() {
	fmt.Println(p.Name)
}

func (p Person) NameToUpper1() {
	p.Name = strings.ToUpper(p.Name)
}

func (p Person) NameToUpper2() string {
	return strings.ToUpper(p.Name)
}

func (p *Person) NameToUpper3() {
	p.Name = strings.ToUpper(p.Name)
}

我们定义了一个Person类,其中有一个属性Name,字符串类型,下面定义了几个方法,PrintMe打印名称,NameToUpper1使用变量接收者,NameToUpper2同样使用变量接收者,不过把转换为大写后的字符串返回,NameToUpper3则使用指针接收者,main函数中的调用如下:

person := Person{Name: "yjp"}
person.PrintMe()

person.NameToUpper1()
person.PrintMe()

person.NameToUpper2()
person.PrintMe()

person.Name = person.NameToUpper2()
person.PrintMe()

person.Name = "yjp"
person.NameToUpper3()
person.PrintMe()

输出为:

yjp
yjp
yjp
YJP
YJP

使用NameToUpper1我们无法修改person变量的Name属性,NameToUpper2虽然无法修改Name,但是可以返回值,还是可以将就的,最好的还是NameToUpper3,直接修改了Name属性。另外,调用NameToUpper3时,可以不使用person变量的指针,类型会进行自动转换。究其原因,使用变量作为接收者,实际是将原始变量进行了深拷贝作为了接收者,指针接收者则是将原变量的地址进行传参。如果我们的结构体比较大,还是建议使用指针作为接收者,防止每次调用方法都要进行深拷贝,影响性能。

对于slice和map类型的接收者,默认当做指针处理。看下面的例子:

type Values []int

func (values Values) PrintValues() {
	fmt.Println(values)
}

func (values Values) AddOne() {
	for i, v := range values {
		values[i] = v + 1
	}
}

type Dict map[string]int

func (d Dict) PrintDict() {
	fmt.Println(d)
}

func (d Dict) AddOneByKey(key string) {
	d[key] = d[key] + 1
}

逻辑很简单,自己看看,main函数中调用

values := Values{1, 2, 3}
values.AddOne()
values.PrintValues()

dict := Dict{"yjp": 1}
dict.AddOneByKey("yjp")
dict.PrintDict()

输出为

[2 3 4]
map[yjp:2]

可见,使用slice和map时,默认传递的就是slice和map的指针,我们可以直接修改其中的值。

猜你喜欢

转载自blog.csdn.net/yjp19871013/article/details/81428565