我不清楚在哪种情况下我会想要使用值接收器而不是总是使用指针接收器 .
从文档中回顾一下:
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
docs 也说"For types such as basic types, slices, and small structs, a value receiver is very cheap so unless the semantics of the method requires a pointer, a value receiver is efficient and clear."
First point 它说它是"very cheap",但问题是它比指针接收器更便宜 . 所以我做了一个小的基准测试(code on gist)向我展示了,即使对于只有一个字符串字段的结构,指针接收器也更快 . 结果如下:
// 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
(编辑:请注意第二点在较新的版本中无效,请参阅注释) .
Second point 它说,这是"efficient and clear"这更多的是品味问题,不是吗?就个人而言,我更喜欢使用相同的方式使用一致性效率在什么意义上?表现明智,指针似乎总是更有效率 . 使用一个int属性的少量测试运行显示Value接收器的最小优势(范围为0.01-0.1 ns / op)
有人能告诉我一个值接收器明显比指针接收器更有意义的情况吗?或者我在基准测试中做错了什么,我是否忽略了其他因素?
2 回答
请注意the FAQ does mention consistency
如上所述in this thread:
现在:
Code Review comment可以提供帮助:
例如,在_352713中找到粗体部分:
另外添加@VonC伟大,内容丰富的答案 .
令我感到惊讶的是,一旦项目变得越来越大,没有人真正提到维护成本,旧开发者离开并且新的开始出现 . 肯定是一种年轻的语言 .
一般来说,我尽量避免使用指针,但他们确实有自己的位置和美感 .
I use pointers when:
使用大型数据集
具有结构维持状态,例如TokenCache,
我确保所有字段都是PRIVATE,只能通过定义的方法接收器进行交互
我没有将此功能传递给任何goroutine
例如:
Reasons why I avoid pointers:
指针不是同时安全的(GoLang的整点)
一次指针接收器,总是指针接收器(对于所有Struct的方法一致)
与"value copy cost"相比,
互斥锁肯定更贵,更慢,更难维护
说到"value copy cost",这真的是一个问题吗?过早优化是万恶之源,你可以随时添加指针
它直接,有意识地迫使我设计小结构
通过设计具有明确意图和明显I / O的纯函数,可以大大避免
指针
我相信
垃圾收集更难用指针
更容易争论封装,责任
保持简单,愚蠢(是的,指针可能很棘手,因为你永远不知道下一个项目的DEV)
单元测试就像穿过粉红色的花园(斯洛伐克只表达?),意味着简单
no NIL if conditions (NIL可以在预期指针的位置传递)
我的经验法则是尽可能多地编写封装方法,例如:
UPDATE:
这个问题激发了我更多地研究这个话题并写了一篇关于它的博客文章https://medium.com/gophersland/gopher-vs-object-oriented-golang-4fa62b88c701