golang值方法和指针方法的区别

文章探讨了在Go语言中,值方法和指针方法的区别,以及它们如何影响调用者。值方法不会改变原始数据,而指针方法可以。同时,文章通过示例说明了在接口使用中,值类型和指针类型如何影响方法集的构建,以及如何导致编译错误。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

环境

Windows 10
golang 1.17

前言

接收者是值类型的方法(例如下面代码中的valueAddAge方法),下文统称为值方法
接收者是指针类型的方法(例如下面代码中的ptrAddAge方法),下文统称为指针方法

代码

package main

import "fmt"

type Person struct {
	age int
}

// 值方法
func (p Person) valueAddAge() {
	p.age++
}

// 指针方法
func (p *Person) ptrAddAge() {
	p.age++
}

func main() {
	// p1是值类型,调用值方法
	p1 := Person{age: 18}
	p1.valueAddAge()
	fmt.Println(p1.age) // 输出18,没有改变

	// p2是值类型,调用指针方法
	p2 := Person{age: 18}
	p2.ptrAddAge()
	fmt.Println(p2.age) // 输出19,有改变

	// p3是指针类型,调用值方法
	p3 := &Person{age: 18}
	p3.valueAddAge()
	fmt.Println(p3.age) // 输出18,没有改变

	// p4是指针类型,调用指针方法
	p4 := &Person{age: 18}
	p4.ptrAddAge()
	fmt.Println(p4.age) // 输出19,有改变
}

1.调用方法时,都是把调用者(调用者是指上面代码中的p1p2p3p4变量)复制一份传递给方法。
2.如果调用者的类型,和接收者的类型不相同,会隐式的把调用者类型转换成接收者的类型。

例如上述代码中的p2p3例子就属于类型不一致的。p2.ptrAddAge()会转换成(&p2).ptrAddAge(),对p2取地址,就得到了一个指针,这样调用者的类型就和接收者一致了,然后把指针复制一份传给方法;

注:仅当p2是可寻址(addressable,或者说左值)的时候,才能对其取地址,否则会报错的

同理,p3.valueAddAge()会转换成(*p3).valueAddAge(),对p3取值,得到了一个值类型的变量,再把变量复制一份传给方法。

如果调用者是指针类型,我们知道,即使将指针复制一份,它指向的原始数据还是不变的,因此在方法中对调用者的数据进行修改,是会影响到调用者的;

但是如果调用者是值类型的,值类型的变量被复制了一份,那新的变量就不是原来的那个变量了,因此在方法里对新变量做修改,是不会影响到原调用者的。

结论

值方法指针方法 的区别,就是看方法里的操作是否会影响到调用者。值方法不会影响,指针方法会影响。

其它:与interface接口组合使用

在上一个场景中,无论调用者接收者是什么类型,调用者都能成功调用到方法。但是,当与 interface 接口组合使用时,情况又会变得不一样,比如以下代码:

package main

import "fmt"

// Human接口
type Human interface {
	getAge() int
}

// Person结构体
type Person struct {
	age int
}

// 实现Human接口的getAge方法,接收者是指针类型
func (rec *Person) getAge() int {
	return rec.age
}

func main() {
	// 创建一个Person对象,值类型
	p1 := Person{age: 18}
	// 把p1赋值给一个类型为Human的接口变量
	var ivar Human = p1 // 这一行会报编译错误
}

上述代码中,我们将结构体变量p1赋值给接口类型变量ivar时,编译器会判断p1变量的方法集里是否实现了接口Human中定义的所有方法,如果没有全部实现,就会报错。

什么是方法集?简单来说就是:

  • 如果p1是值类型,那它的方法集就是它的所有值方法(接收者为值类型的方法)
  • 如果p1是指针类型,那它的方法集就是它的所有值方法 + 指针方法(接收者为指针类型的方法)

很明显,p1是值类型,而它只有一个指针方法,也就是说,它的方法集是空的,没有实现Human接口中定义的方法,所以编译器报错了。

参考

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值