四条原则彻底搞懂值接收者和指针接收者

感性认识:

一、值类型接收者的方法 相当于 值类型的函数入参
二、指针类型接收者的方法 相当于 指针类型的函数入参

代码演示:

package main

import "fmt"

func main() {
	c1 := Child{1} // c1变量保存的是值类型
	c1.Age() // 查看age
	fmt.Printf("%v", c1)
	c1.GrowUp() // 值类型调用者,指针类型接受者,age发生改变,实际(&c1).GrowUp()
	fmt.Printf("%v", c1)
	c1.TryGrowUp() // 值类型调用者,值类型接受者,age没有改变
	fmt.Printf("%v", c1)

	fmt.Printf("\n-----------------------\n")

	c2 := &Child{1} // c2变量保存的是指针类型
	c2.Age() // 查看age
	fmt.Printf("%v", c2)
	c2.GrowUp() // 指针类型调用者,指针类型接受者,age发生改变
	fmt.Printf("%v", c2)
	c2.TryGrowUp() // 指针类型调用者,值类型接受者,age没有改变,实际(*c2).TryGrowUp()
	fmt.Printf("%v", c2)

	fmt.Printf("\n-----------------------\n")

	var p1 People = &Child{1} // p1是一个接口,若将 &Child{1} 改为 Child{1} 则可通过编译
	p1.Age()
	fmt.Printf("%v", p1)
	p1.GrowUp()
	fmt.Printf("%v", p1)
	c1.TryGrowUp()
	fmt.Printf("%v", p1)
}

type People interface {
	Age()
	GrowUp()
}

type Child struct {
	age int
}

func (c Child) Age() int {
	return c.age
}

func (c *Child) GrowUp() {
	c.age++
}

func (c Child) TryGrowUp() {
	c.age++
}

结果:

{1}{2}{2}

&{1}&{2}{2}

cannot use &(Child literal) (value of type *Child) as People value in variable declaration: wrong type for method Agecompiler

结论

  1. 值接收者的方法不会修改调用者
  2. 指针接收者的方法会修改调用者
  3. 语言有语法糖对使用原始对象的调用者进行优化
  4. 当给接口传递的是指针,同时实现接口的对象方法中存在值接收者和指针接收者实现将不会通过编译,理由是两种接收者对数据的表现行为不一致,简单说既:指针类型可能会修改调用者,而值接收者不会
posted @ 2020-10-04 00:10  r1chard  阅读(449)  评论(0)    收藏  举报