go语言结构体定义方法时,值作为接收者和指针作为接收者的区别

直接上代码,具体再来解释

package main

import "fmt"

type coder interface {
	code()
	debug()
}

type Gopher struct {
	num      int
	language string
}

func (p Gopher) code() {
	p.num++
	fmt.Printf("I am coding %s language, num is %d\n", p.language, p.num)
}

func (p *Gopher) debug() {
    p.num++
	fmt.Printf("I am debuging %s language, num is %d\n", p.language, p.num)
}

/* 
  1、使用值调用
*/
func main() {
	var c Gopher = Gopher{1, "Go"}
	c.code()
	c.debug()
	c.code()
}

/* 
  2、使用指针调用
*/
// func main() {
// 	var c *Gopher = &Gopher{1, "Go"}
// 	c.code()
// 	c.debug()
// 	c.code()
// }

/* 
  3、使用interface作为调用者
*/
// func main() {
// 	var c coder = &Gopher{1, "Go"}
// 	c.code()
// 	c.debug()
// 	c.code()
// }

/* 
  4、使用interface作为调用者
         cannot use Gopher literal (type Gopher) as type coder in assignment:
                 Gopher does not implement coder (debug method has pointer receiver)
*/
// func main() {
// 	var c coder = Gopher{1, "Go"}  //此处报错
// 	c.code()
// 	c.debug()
// 	c.code()
// }
第一段代码输出为:
I am coding Go language, num is 2
I am debuging Go language, num is 2
I am coding Go language, num is 3

我们可以发现输出结果为2,2,3
第一次:c.code()调用时,我们执行了p.num++,此时输出p.num应该为2,毫无疑问,就是进行了+1操作;
第二次:c.debug()调用时,我们同样执行了一次p.num++,此时输出p.num仍然为2,假设第一次调用修改了对象c中num的值是 对象本身,那么现在应该输出为3,可见,第一次操作的仅仅是c对象拷贝的一个副本,对副本num进行了+1操作。
第三次:c.code()继续调用,这次执行p.num++输出为3,由此可见,我们第二次执行的操作是对c对象本身的操作。
由这个例子我们可以知道,由值作为接收者,被调用时,是对对象的拷贝,指针作为接收者,被调用时,是对对象本身的操作

第二段代码输出为:
I am coding Go language, num is 2
I am debuging Go language, num is 2
I am coding Go language, num is 3

输出结果为2,2,3,和第一段代码一样,所以使用指针调用和使用值调用,操作时相同的,go对其做了隐式操作。也就是说,不管方法的接收者是什么类型,该类型的值和指针都可以调用,不必严格符合接收者的类型。

第三段代码输出为:
I am coding Go language, num is 2
I am debuging Go language, num is 2
I am coding Go language, num is 3
第四段代码输出为:
      cannot use Gopher literal (type Gopher) as type coder in assignment:
                 Gopher does not implement coder (debug method has pointer receiver)

我们可以看到第三段可以正常输出,第四段编译期间报错。和第一种第二种不同,我们使用了interface来作为调用者,我分别用值类型和指针型去接收struct的对象。如果和java中的泛型一样,第三种、第四种输出结果应该和第一种、第二种一样,但是第四种却报错说该“Gopher does not implement coder”,也就是值类型的struct Gopher没有实现interface coder的code()方法。我们着重看接收者的区别,我们定义Gopher的code和debug方法时,一个是值作为接收者,一个是指针作为接收者,在我们使用interface(coder)去接收struct(Gopher)时报错,说明struct(Gopher)没有实现interface(coder)中的方法。因此结论为:接收者是值类型的方法,相当于自动实现了接收者是指针类型的方法;而接收者是指针类型的方法,不会自动生成对应接收者是值类型的方法。

如果方法的接收者是值类型,无论调用者是对象还是对象指针,修改的都是对象的副本,不影响调用者;如果方法的接收者是指针类型,则调用者修改的是指针指向的对象本身。

以上说的都是一些结论性的东西,并没有打开go的这些语法糖做深入的说明,如果有哪位对这方面有深入的研究,可以在下文回复,我们一起探讨。

另外说明:本文仅是对自己理解的记录,参考了博客园中 Stefno 的文章,文章是对interface的讲解,写的很好。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值