何时在golang中使用指针

一个普遍的观点是,当我们在使用指针时,我们的应用程序会更快,因为我们将避免一直复制数据。

但是,在Go中传递指针通常比传递值要慢。这是Go成为垃圾收集语言的结果。当我们将指针传递给函数时,Go需要执行转义分析以弄清楚该变量是否应存储在堆或堆栈中。这已经增加了一些开销,此外,将变量存储在堆上时,GC运行时也会浪费时间。

Go的一项巧妙功能是,我们可以通过运行go build -gcflags =“-m”来检查转义分析的功能。如果运行此命令,Go会告诉我们变量是否会转储到堆中。

如果一个变量没有逃逸到堆中,它就存在于堆栈中。而且堆栈不需要垃圾收集器来清理变量,而只是push和pop操作。

如果仅按值传递所有内容,则始终在堆栈上运行,而不必承担垃圾收集的开销。(默认情况下,GC仍将运行。但是堆上的内存越少,GC要做的工作就越少)。

现在我们知道使用指针可能会对性能产生负面影响,但是什么时候要使用指针?

复制大型struct

当我们的struct中包含大量数据时,指针可能会有所帮助,垃圾收集器的开销可能会被复制大量数据时获得的开销所抵消。

但是struct应该达到多大才算大呢?这个没有一个具体的数字,但是我们可以使用Go内置的基准测试工具来获得一个合理的值。

易变的变量

更改传递给函数的变量的唯一方法是传递指针。默认情况下,按值传递表示我们所做的更改位于正在处理的副本上。 因此,它们不会反映在调用函数中。

API一致性

如果需要至少一个指针接收器,则最好在各处都使用指针接受其。即使不是所有的方法都可能使我们的struct,这将使我们的API保持一致。

区分零值和未设置值

如果我们使用的是值,则始终会得到默认的零值。在某些情况下,我们可能想真正知道是否缺少或已填写完毕。 通过使用指针,默认零值是nil指针,可用于表示不存在值。

Note

另外,切片、字符串和映射等许多类型都包含指向基础数据的指针,而将指针传递给这些类型几乎是没有道理的。