Golang-对象方法和实现接口时,方法接受者是指针还是对象的区别

本文深入探讨了GoLang中对象方法的实现方式,包括实例和指针作为方法接受体的区别,以及方法调用是否产生值复制的影响。同时,解析了GoLang接口实现的特殊规则,即无需显示声明实现接口,只需确保结构体拥有相同签名的方法即可。

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

方法格式

golang和java的对象方法实现上有很大的区别,在golang中,一个对象的方法定义如下

func (o Object) FuncName(args...) (results...){}

其中 o 代表的是函数的接受体,意思是这个函数属于对象 o 的方法。

args 表示形参列表。

results 表示函数返回值列表,对于无返回值的方法可以为空,和java void方法一样

方法接受体 o 实例和指针的区别

注意看以下方法的接受体,一个是实例,一个是指针

type FragmentImpl struct {
	i int
}
func (f FragmentImpl) Exec() {
	fmt.Printf("%p\n", &f)
	f.i = 10
}
func (f *FragmentImpl) Exec2() {
	fmt.Printf("%p\n", f)
	f.i = 10
}
func main() {
	fragment := FragmentImpl{1}
	fmt.Printf("%p --  %v \n", &fragment,fragment)
	fragment.Exec()
	fmt.Printf("%p --  %v \n", &fragment,fragment)
	(&fragment).Exec()
	fmt.Printf("%p --  %v \n", &fragment,fragment)

	fmt.Println("----------------------------")

	fragment2 := &FragmentImpl{1}
	fmt.Printf("%p --  %v \n", fragment2,fragment2)
	fragment2.Exec2()
	fmt.Printf("%p --  %v \n", fragment2,fragment2)
	(*fragment2).Exec2()
	fmt.Printf("%p --  %v \n", fragment2,fragment2)
}

OUT:
0xc042060080 --  {1} 
0xc0420600b0
0xc042060080 --  {1} 
0xc0420600c0
0xc042060080 --  {1} 
----------------------------
0xc0420600d0 --  &{1} 
0xc0420600d0
0xc0420600d0 --  &{10} 
0xc0420600d0
0xc0420600d0 --  &{10} 

可以看出,对于Exec(),虽然方法接受体是实例,但是不管FragmentImpl的实例还是实例的地址指针都能够调用成功,但是不管以何种形式调用,都会产生值复制(地址不同),不会对原始对象的属性产生更改。

对于Exec2(),方法的接受体是结构体指针,同样的也可以用实例或者指针去调用,而且能够对原始对象产生修改行为。

所以,在golong中,会不会产生值复制,关键在于方法的接受体是对象还是指针,而不是调用方法的类型,因为golang会自动解引用。不过我觉得,即使以*T指针的形式调用方法,实际上也是会产生复制的,不过此时复制的是指针这个“值”,所以在方法中可以通过访问指针修改原生的值。

接口的实现

golang中接口的实现比较奇怪,实现类不需要像java一样通过implments显示指定实现的接口类,只需要包含和接口一样的函数,就认为这个结构体实现了接口。

type Fragment interface {
	Exec()
}

type FragmentImp struct {
	i int
}
func (f *FragmentImp) Exec() {
	fmt.Printf("%p\n", f)
	f.i = 10
}

type FragmentImp2 struct {
	i int
}
func (f FragmentImp2) Exec() {
	fmt.Printf("%p\n", f)
	f.i = 10
}

func main() {
	//var f Fragment = FragmentImp{1} //Exec method has pointer receiver
	//f.Exec()
	var f2 Fragment = &FragmentImp{1}
	f2.Exec()

	var f3 Fragment = &FragmentImp2{1}
	f3.Exec()
	var f4 Fragment = FragmentImp2{1}
	f4.Exec()
}

只要 funcName,args...,results...和interface一样,就认为结构体实现了接口,不管方法的接受体是实例还是指针,不过需要注意的是,如果实现接口的是指针,那么不能把结构体实例值 赋值给接口。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值