golang方法接收者

博客 分享
0 205
张三
张三 2022-05-31 14:59:54
悬赏:0 积分 收藏

golang 方法接收者

  • [定义]: golang的方法(Method)是一个带有receiver的函数Function,Receiver是一个特定的struct类型,当你将函数Function附加到该receiver, 这个方法Method就能获取该receiver的属性和其他方法。
  • [面向对象]: golang方法Method允许你在类型上定义函数,是一个面向对象的行为代码, 这也有一些益处:同一个package可以有相同的方法名, 但是函数Function却不行。

func (receiver receiver_type) some_func_name(arguments) return_values

从应用上讲,方法接受者分为值接收者,指针接收者,初级golang学者可能看过这两个接收者实际表现, 但是一直很混淆,很难记忆。

本次我们使用地址空间的角度来剖析实质,强化记忆。

值类型方法接收者

值接受者: receiver是struct等值类型。

下面定义了值类型接受者Person, 尝试使用Person{}, &Person{}去调用接受者函数。

package mainimport "fmt"type Person struct {	name  string	age int}func (p Person) say() {	fmt.Printf("I (%p) ma %s, %d years old \n",&p, p.name,p.age)}func (p Person) older(){  // 值类型方法接受者: 接受者是原类型值的副本	p.age = p.age +1	fmt.Printf("I (%p) am %s, %d years old\n", &p, p.name,p.age)}func main() {	 p1 := Person{name: "zhangsan", age: 20}	 p1.older()	 p1.say()	 fmt.Printf("I (%p) am  %s, %d years old\n",&p1, p1.name,p1.age)	 p2 := &Person{ name: "sili", age: 20}	 p2.older()   // 即使定义的是值类型接受者, 指针类型依旧可以使用,但我们传递进去的还是值类型的副本	 p2.say()	 fmt.Printf("I (%p) am %s, %d years old\n",p2, p2.name,p2.age)}

尝试改变p1=Person{},p2=&Person{}的字段值:

I (0xc000098078) am zhangsan, 21 years oldI (0xc000098090) ma zhangsan, 20 years oldI (0xc000098060) am  zhangsan, 20 years oldI (0xc0000980c0) am sili, 21 years oldI (0xc0000980d8) ma sili, 20 years oldI (0xc0000980a8) am sili, 20 years old

p1=Person{} 未能修改原p1的字段值; p2=&Person{}也未能修改原p2的字段值。

  • 通过Person{}值去调用函数, 传入函数的是原值的副本, 这里通过第一行和第三行的%p印证 (%p:输出地址值, 这两个非同一地址)。
  • 即使定义的是值类型接收者,指针类型依旧可以调用函数, 但是传递进去的还是值类型的副本。

带来的效果是:对值类型接收者内的字段操作,并不影响原调用者。

指针类型接受者

方法接收者也可以定义在指针上,任何尝试对指针接收者的修改,会体现到调用者。

package mainimport  "fmt"type Person struct{	name string	age int}func  (p Person) say(){	fmt.Printf("I (%p)  am %s, %d years old\n", &p, p.name,p.age)}func (p *Person) older(){   // 指针接受者,传递函数内部的是原类型值(指针), 函数内的操作会体现到原指针指向的空间	p.age	= p.age	+1	fmt.Printf("I (%p)  am %s, %d years old\n", p, p.name,p.age)}func main() {	p1 := Person{"zhangsan",20}	p1.older()  // 虽然定义的是指针接受者,但是值类型依旧可以使用,但是会隐式传入指针值	p1.say()	fmt.Printf("I (%p)  am %s, %d years old\n", &p1, p1.name,p1.age)	p2:= &Person{"sili",20}	p2.older()	p2.say()	fmt.Printf("I (%p)  am %s, %d years old\n", p2, p2.name,p2.age)}

尝试改变p1= Person{}, p2=&Person{}字段值

I (0xc000098060)  am zhangsan, 21 years oldI (0xc000098078)  am zhangsan, 21 years oldI (0xc000098060)  am zhangsan, 21 years oldI (0xc000098090)  am sili, 21 years oldI (0xc0000980a8)  am sili, 21 years oldI (0xc000098090)  am sili, 21 years old

p1=Person{} 成功修改字段值,p2=&Person{}也成功修改字段值。

  • 通过p1也可以调用指针函数接收者, 但是实际会隐式传递指针值。
  • 指针接收者,入参是原指针值,函数内的操作会体现到原调用者

带来的效果: 任何对指针接收者的修改会体现到 原调用者。

什么时候使用指针接收者

  1. 需要对接受者的变更能体现到原调用者
  2. 当struct占用很大内存,最好使用指针接受者,否则每次调用接受者函数 都会形成struct的大副本

golang方法的几种姿势

接上例子:

  1. 将接收者函数当扩展函数
	Person.say(p1)	(*Person).older(p2)

依旧是 值类型/指针类型方法接收者的效果。

I (0xc0000040d8)  am zhangsan, 21 years oldI (0xc0000040a8)  am sili, 22 years old

这种姿势相对于面向对象的接收者不常见。

  1. golang 方法链条
func (p Person) printName() Person{  fmt.Printf("Name:%s", p.Name)  return p}
  1. Non_struct类型golang方法
type myFloat float64func (m myFloat) ceil() float64 {   return  math.Ceil(float64(m))}

以上是有态度的马甲记录的有关golang 方法接收者的全部用法,通过%p,我们探究了值类型/指针接收者的调用原理。

posted @ 2022-05-31 14:51 博客猿马甲哥 阅读(0) 评论(0) 编辑 收藏 举报
回帖
    张三

    张三 (王者 段位)

    821 积分 (2)粉丝 (41)源码

     

    温馨提示

    亦奇源码

    最新会员