Go 值接收器与指针接收器的选择

1,504 阅读2分钟

简介

对于很多初学者来说接收器应该是指针类型还是值类型可能会存在困惑,什么场景下应该定义为指针类型的接收器,什么场景下应该定义值类型接收器?下面通过介绍常见的应该场景来帮忙理解上手。

接收器定义

  • 值类型接收器
    type Event struct {
       ID   string
       Name string
    }
    
    // SetName 定义值类型接收器的方法
    func (e Event) SetName(name string) {
       e.Name = name
    }
    
  • 指针类型接收器
    type Event struct {
       ID   string
       Name string
    }
    
    // SetName 定义指针类型接收器的方法
    func (e *Event) SetName(name string) {
       e.Name = name
    }
    

什么时候使用值接受器或指针接收器

使用指针接收器

  • 如果方法需要去修改接收器,则需要将接收器定义为指针类型
  • 如果接收器是一个struct类型并包含sync.Mutex或synchronizing属性,则接收器需要定义为指针类型来避免复制
  • 如果接收器是一个非常大struct或array,有多大?假设它相当于将所有元素作为参数传递给方法。如果感觉太大,对接收器来说也太大了。
  • 如果接收器是一个struct、array或slice,且他的元素是指针类型或可变的字段,则推荐定义为指针类型,因为它会使读者更清楚意图。
  • 当有疑问,选择用指针还是值接收器,则推荐使用指针接收器

使用值接收器

  • 如果接收器为map、func、chan或slice等类型
  • 如果接收器是一个小数组或结构,它自然是一个值类型(例如,类似 time.Time 类型),没有可变字段和指针,或者只是一个简单的基本类型,如 int 或 string,则 值接收器是有道理的。 值接收器可以减少可以生成的垃圾量; 如果将值传递给值方法,则可以使用堆栈上的副本而不是在堆上分配。 (编译器试图巧妙地避免这种分配,但它并不总是成功。)不要在没有首先进行分析的情况下选择值接收器类型。

备注:同一个struct的方法接收器的定义,不建议即有指针类型又有值类型。要么全部定义为值类型,要么全部定义为指针类型