Go语言中值接收者和指针接收者的区别?

鼠扑  论坛元老 | 2024-12-31 20:35:23 | 显示全部楼层 | 阅读模式
打印 上一主题 下一主题

主题 2024|帖子 2024|积分 6072

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

x
在 Go 语言中,值接收者指针接收者是方法界说中的两种接收者范例。它们的主要区别在于方法调用时的举动、接收者是否可以被修改,以及性能上的差异。

值接收者

界说

值接收者的方法接收的是调用对象的一个副本,方法内部对该副本的修改不会影响原对象。
特点


  • 传递的是值的副本

    • 方法内操作的是值的拷贝,修改不会影响原对象。

  • 适用于不可变的对象

    • 如果方法不必要修改对象的状态,可以使用值接收者。

  • 适用于小对象

    • 值接收者传递整个对象副本,得当较小的对象。

  • 可用值或指针调用

    • 无论是值还是指针,都可以调用值接收者的方法,Go 会主动处置惩罚。

示例

  1. package main
  2. import "fmt"
  3. type Rectangle struct {
  4.     Width, Height int
  5. }
  6. // 值接收者方法
  7. func (r Rectangle) Area() int {
  8.     return r.Width * r.Height
  9. }
  10. // 修改操作(仅对副本有效)
  11. func (r Rectangle) SetWidth(w int) {
  12.     r.Width = w
  13. }
  14. func main() {
  15.     rect := Rectangle{Width: 10, Height: 5}
  16.     fmt.Println("Area:", rect.Area()) // 输出: Area: 50
  17.     rect.SetWidth(20)
  18.     fmt.Println("Width after SetWidth:", rect.Width) // 输出: Width after SetWidth: 10
  19. }
复制代码
说明:调用 SetWidth 方法时,rect.Width 没有改变,因为 SetWidth 操作的是值的副本。

指针接收者

界说

指针接收者的方法接收的是调用对象的地址,方法内部对接收者的修改会直接作用于原对象。
特点


  • 传递的是指针

    • 方法操作的是对象的指针,修改接收者的状态会直接影响原对象。

  • 适用于可变的对象

    • 如果方法必要修改对象的状态,必须使用指针接收者。

  • 适用于大对象

    • 指针接收者避免了拷贝大对象的开销。

  • 只能用值或指针调用

    • 无论对象是值还是指针,都可以调用指针接收者的方法,Go 会主动转换。

示例

  1. package main
  2. import "fmt"
  3. type Rectangle struct {
  4.     Width, Height int
  5. }
  6. // 指针接收者方法
  7. func (r *Rectangle) Scale(factor int) {
  8.     r.Width *= factor
  9.     r.Height *= factor
  10. }
  11. func main() {
  12.     rect := Rectangle{Width: 10, Height: 5}
  13.     rect.Scale(2)
  14.     fmt.Println("Scaled Width:", rect.Width) // 输出: Scaled Width: 20
  15.     fmt.Println("Scaled Height:", rect.Height) // 输出: Scaled Height: 10
  16. }
复制代码
说明:调用 Scale 方法时,rect.Width 和 rect.Height 的值被直接修改。

值接收者与指针接收者的主要区别

特性值接收者指针接收者传递内容对象的副本对象的地址方法是否能修改原对象否是适用场景- 不必要修改接收者
- 对象较小,拷贝开销小- 必要修改接收者
- 对象较大,拷贝开销大调用方式值或指针都可以调用值或指针都可以调用性能较低性能:对于大对象,会复制整个对象较高性能:传递指针,避免了对象的复制
值接收者与指针接收者的调用规则

无论方法是值接收者还是指针接收者:

  • 值调用值接收者:直接使用。
  • 指针调用值接收者:Go 会主动解引用指针并传递对象值的副本。
  • 值调用指针接收者:Go 会主动获取对象的地址。
  • 指针调用指针接收者:直接使用。
示例

  1. package main
  2. import "fmt"
  3. type Counter struct {
  4.     Count int
  5. }
  6. func (c Counter) Increment() {
  7.     c.Count++
  8. }
  9. func (c *Counter) Decrement() {
  10.     c.Count--
  11. }
  12. func main() {
  13.     c := Counter{Count: 10}
  14.     // 调用值接收者方法
  15.     c.Increment()
  16.     fmt.Println("After Increment:", c.Count) // 输出: After Increment: 10 (未修改)
  17.     // 调用指针接收者方法
  18.     c.Decrement()
  19.     fmt.Println("After Decrement:", c.Count) // 输出: After Decrement: 9 (被修改)
  20. }
复制代码

如何选择值接收者或指针接收者?



  • 选择值接收者

    • 方法不必要修改接收者。
    • 对象较小(如基本数据范例或简朴结构体)。
    • 提拔代码可读性。

  • 选择指针接收者

    • 方法必要修改接收者。
    • 对象较大,拷贝成本高。
    • 必要保证方法在全部调用场景中的举动同等(如使用接口时,避免副本调用导致的问题)。

示例

如果结构体实现接口时:


  • 建议使用指针接收者,以确保通过接口调用时能修改对象。
  1. type Resizable interface {
  2.     Resize(factor int)
  3. }
  4. type Rectangle struct {
  5.     Width, Height int
  6. }
  7. func (r *Rectangle) Resize(factor int) {
  8.     r.Width *= factor
  9.     r.Height *= factor
  10. }
复制代码

总结



  • 值接收者得当不可变操作;指针接收者得当可变操作。
  • 指针接收者避免了拷贝大对象的开销,但增加了代码复杂性。
  • 选择接收者范例时,应根据方法的用途和对象的巨细权衡。

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

鼠扑

论坛元老
这个人很懒什么都没写!
快速回复 返回顶部 返回列表