ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

Go高性能之方法接收器 - 指针vs值

2022-08-01 20:03:23  阅读:156  来源: 互联网

标签:接收器 Inside 接收者 Person vs Go 方法 指针


示例

如果您是 Go 新手,那么您一定遇到过方法和函数的概念。让我们找出两者之间的区别-

通过指定参数的类型、返回值和函数体来声明函数。

type Person struct { 
    Name string 
    Age int 
}func NewPerson(name string, age int) *Person { 
  return &Person{ 
     Name: name, 
     Age: age, 
  } 
}

方法只是一个带有接收器参数的函数。它使用相同的语法声明,并添加了接收者

func (p *Person) isAdult bool { 
  return p.Age > 18 
}

在上面的方法声明中,我们在类型上声明了isAdult方法。*Person

现在我们将看到值接收器指针接收器之间的区别

值接收者复制类型并将其传递给函数。函数堆栈现在拥有一个相等的对象,但在内存上的不同位置。这意味着对传递的对象所做的任何更改都将保留在该方法的本地。原始对象将保持不变。

指针接收器将类型的地址传递给函数。函数堆栈具有对原始对象的引用。因此对传递对象的任何修改都会修改原始对象。

让我们通过示例来理解这一点-

package main
import (
  "fmt"
)
type Person struct {
    Name string
    Age  int
}
func ValueReceiver(p Person) {
    p.Name = "John"
    fmt.Println("Inside ValueReceiver : ", p.Name)
}
func PointerReceiver(p *Person) {
    p.Age = 24
    fmt.Println("Inside PointerReceiver model: ", p.Age)
}
func main() {
    p := Person{"Tom", 28}
    p1:= &Person{"Patric", 68}
    ValueReceiver(p)
fmt.Println("Inside Main after value receiver : ", p.Name)
    PointerReceiver(p1)
fmt.Println("Inside Main after value receiver : ", p1.Age)
}

------------
Inside ValueReceiver :  John
Inside Main after value receiver :  Tom
Inside PointerReceiver :  24
Inside Main after pointer receiver :  24

这表明具有值接收者的方法修改了对象的副本,而原始对象保持不变。Like- 通过 ValueReceiver 方法将一个人的姓名从 Tom 更改为 John,但这种更改并未反映在 main 方法中。另一方面,带有指针接收器的方法会修改实际对象。Like- 通过 PointerReceiver 方法将人的年龄从 68 岁更改为 24 岁,同样的变化反映在 main 方法中。您可以通过在指针或值接收器操作之前和之后打印出对象的地址来检查事实。

那么如何在 Pointer 和 Value 接收器之间进行选择呢?

如果要更改方法中接收器的状态,操作它的值,请使用指针接收器。使用按值复制的值接收器是不可能的。对值接收器的任何修改对于该副本都是本地的。如果您不需要操作接收器值,请使用值接收器

指针接收器避免在每个方法调用上复制值。如果接收器是一个大型结构,这可能会更有效,

值接收器是并发安全的,而指针接收器不是并发安全的。因此,程序员需要照顾它。

汇总:

  • 如果接收者是 map、func 或 chan,不要使用指向它的指针。
  • 尽量对所有方法使用相同的接收器类型。
  • 如果接收者是一个切片并且该方法没有重新切片或重新分配切片,则不要使用指向它的指针。
  • 如果方法需要改变接收者,接收者必须是一个指针。
  • 如果接收者是包含sync.Mutex或类似同步字段的结构,则接收者必须是指针以避免复制。
  • 如果接收器是大型结构或数组,则指针接收器效率更高。大有多大?假设它相当于将其所有元素作为参数传递给方法。如果感觉太大,那么对于接收器来说也太大了。
  • 函数或方法是否可以同时或在从此方法调用时改变接收者?调用方法时,值类型会创建接收器的副本,因此外部更新不会应用于此接收器。如果更改必须在原始接收器中可见,则接收器必须是指针。
  • 如果接收器是结构体、数组或切片,并且它的任何元素都是指向可能发生变化的东西的指针,则更喜欢指针接收器,因为它会使读者更清楚意图。
  • 如果接收者是一个小数组或结构,它自然是一个值类型(例如,类似time.Time类型),没有可变字段和指针,或者只是一个简单的基本类型,如 int 或 string,则值接收器更好
    值接收器可以减少可以生成的垃圾量;如果将值传递给值方法,则可以使用堆栈上的副本而不是在堆上分配。(编译器试图巧妙地避免这种分配,但它并不总是成功。)不要在没有首先进行分析的情况下选择值接收器类型。
  • 最后,当有疑问时,使用指针接收器。

 

原文: https://medium.com/globant/go-method-receiver-pointer-vs-value-ffc5ab7acdb

标签:接收器,Inside,接收者,Person,vs,Go,方法,指针
来源: https://www.cnblogs.com/sunsky303/p/16541676.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有