当前位置: 首页 > 面试题库 >

值接收器与指针接收器

葛宏爽
2023-03-14
问题内容

对于我来说,目前尚不清楚,在这种情况下,我想使用值接收器而不是始终使用指针接收器。
回顾一下文档:

type T struct {
    a int
}
func (tv  T) Mv(a int) int         { return 0 }  // value receiver
func (tp *T) Mp(f float32) float32 { return 1 }  // pointer receiver

文档 还说:“对于基本类型,切片和小型结构之类的类型,值接收器非常便宜,因此,除非该方法的语义要求使用指针,否则值接收器是高效且清晰的。”

首先,
它说“非常便宜”,但问题是它比指针接收器便宜。因此,我做了一个小的基准测试(基于要点的代码),向我展示了,即使对于只有一个字符串字段的结构,指针接收器也更快。结果如下:

// Struct one empty string property
BenchmarkChangePointerReceiver  2000000000               0.36 ns/op
BenchmarkChangeItValueReceiver  500000000                3.62 ns/op


// Struct one zero int property
BenchmarkChangePointerReceiver  2000000000               0.36 ns/op
BenchmarkChangeItValueReceiver  2000000000               0.36 ns/op

(编辑:请注意,第二点在较新的go版本中变得无效,请参阅注释)
第二点
说,这是“高效而清晰的”,更多的是品味问题,不是吗?就个人而言,我更喜欢在各处使用相同的方式来保持一致性。效率在什么意义上?在性能方面,指针似乎几乎总是更高效。很少有具有int属性的测试运行显示了Value接收器的最小优势(范围为0.01-0.1
ns / op)

有人可以告诉我一个值接收器比指针接收器更有意义的情况吗?还是我在基准测试中做错了什么,我是否忽略了其他因素?


问题答案:

请注意,FAQ确实提到了一致性

接下来是一致性。如果该类型的某些方法必须具有指针接收器,则其余方法也应该具有指针接收器,因此无论如何使用该类型,方法集都是一致的。有关详细信息,请参见有关方法集的部分。

如本线程所述:

关于指针与接收器的值的规则是,可以在指针和值上调用值方法,但是只能在指针上调用指针方法

现在:

有人可以告诉我一个值接收器比指针接收器更有意义的情况吗?

该代码评审意见可以帮助:

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

粗体部分例如在中找到net/http/server.go#Write()

// Write writes the headers described in h to w.
//
// This method has a value receiver, despite the somewhat large size
// of h, because it prevents an allocation. The escape analysis isn't
// smart enough to realize this function doesn't mutate h.
func (h extraHeader) Write(w *bufio.Writer) {
...
}


 类似资料:
  • 问题内容: 我很难理解为什么这些规则与指针类型.vs的方法集相关联。值类型 有人可以解释一下原因吗(从界面表的角度) (威廉·肯尼迪博客的摘录) 规格摘要 方法集 类型可能具有与之关联的方法集。接口类型的方法集是其接口。任何其他类型T的方法集都包含以接收者类型T声明的所有方法。相应指针类型 T的方法集是所有以接收者 T或T声明的方法的集合(也就是说,它还包含方法T集)。进一步的规则适用于包含匿名字

  • 问题内容: 在用于golang的mongodb驱动程序中,包含以下代码: 接口清零器的定义如下: 当我实现我的结构 有用。但是,当我使用指针接收器实现IsZero方法时: 类型声明失败,并且IsZero无法执行。 谁可以给我解释一下这个? 问题答案: 据推测某处之上的有上的开关 如果您在Reflection包中查看,则此处的文档 是其中一种,又是另一种。在switch语句中,它不匹配,因为该方法的

  • 问题内容: 我一直在从关于指针接收器的话题中出错,我决定用谷歌搜索术语的含义,并且阅读了有关指针接收器的不同资源和文档。例如:http : //golang.org/doc/faq和http://jordanorelli.com/post/32665860244/how- to-use-interfaces-in-go。 虽然,尽管他们谈论这些术语,但仍未能准确定义它们。不过,从上下文来看,我认为

  • 问题内容: 我最近正在研究虹膜框架。在实现处理程序时遇到一个问题。如下所示: 为了使用此控制器,我实现了以下输入脚本: 但是,当我编译代码时,收到以下错误消息: 在我将声明更改为: 然后,编译器通过,没有任何抱怨。 问题是:我认为以下语句是相等的,因为GO编译器将在表下进行转换: 为什么我不能用作为参数,而不是作为参数传递给? 感谢您的宝贵时间和分享。 问题答案: 参阅文件: 类型可能具有与之关联

  • 当结构体实现一个接口时,可以在方法中设置一个接收者,比如对于以下接口: type Inter interface { foo() } 结构体在实现它时,方法的接收者类型可以是:值、指针。比如: type S struct {} func (s S) foo() {} // 值类型 func (s *S) foo() {} // 或者指针类型 在使用结构体初始化接口变量时,结构体的类型

  • 问题内容: 我有这个示例代码 无法正常工作,因为其接收器不是指针类型。 如果我将方法更改为指针接收器,那么我希望它可以正常工作,如下所示: 编译会导致以下错误: 如何在不创建副本的情况下使接口 和 方法实现实际实例的值? 这是一个可入侵的代码段:https : //play.golang.org/p/ghW0mk0IuU 问题答案: 您指向结构的指针应实现该接口。这样,您可以修改其字段。 查看我如