值接收器与指针接收器

我不清楚在哪种情况下我想使用值接收器而不是总是使用指针接收器。


回顾一下文档:


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

的文档也说“对于类型,如基本类型,切片和小结构,值接收机是非常便宜,所以,除非所述方法的语义需要一个指针,一个值是接收机有效和明确的。”


他们文档说的第一点是值接收器“非常便宜”,但问题是它是否比指针接收器便宜。所以我做了一个小的基准测试(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

(编辑:请注意,第二点在较新的 go 版本中无效,请参阅评论。)


第二点文档说价值接收者是“高效和清晰”的,这更像是一个品味问题,不是吗?就个人而言,我更喜欢通过在任何地方使用相同的东西来保持一致性。什么意义上的效率?性能方面似乎指针几乎总是更有效。很少有具有一个 int 属性的测试运行显示 Value 接收器的最小优势(范围为 0.01-0.1 ns/op)


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


慕姐8265434
浏览 241回答 3
3回答

郎朗坤

这是一个语义问题。想象一下,您编写了一个以两个数字作为参数的函数。您不想突然发现这些数字中的任何一个都被调用函数改变了。如果您将它们作为指针传递,那是可能的。很多事情都应该像数字一样。诸如点、二维向量、日期、矩形、圆等之类的东西。这些东西没有身份。同一位置且半径相同的两个圆不应相互区分。它们是值类型。但是像数据库连接或文件句柄这样的东西,GUI 中的按钮是身份很重要的东西。在这些情况下,您需要一个指向对象的指针。当某些东西本质上是值类型(例如矩形或点)时,最好能够在不使用指针的情况下传递它们。为什么?因为这意味着你肯定会避免改变对象。它向代码的读者阐明了语义和意图。很明显,接收对象的函数不能也不会改变对象。
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Go