在设计和编写库时,我应该何时使用指针作为参数,何时不应该使用?

时间:2016-01-25 20:00:02

标签: pointers go

很抱歉,如果我的问题看起来很愚蠢。我的背景是PHP,Ruby,Python,Lua和类似的语言,我对现实场景中的指针一无所知。

从我在互联网上阅读的内容以及我在一个问题(When is a pointer idiomatic?)中得到的回复中,我了解到:

  • 复制大数据时应使用指针。而不是获取整个对象层次结构,接收它的地址并访问它。
  • 当你在修改它的结构上有一个函数时,必须使用指针。

所以,指针似乎是一件好事:我应该总是将它们作为函数参数获取,因为它们非常轻量级,如果我最终不需要修改结构上的任何内容,那就没关系。

然而,直观地看着这句话,我觉得这听起来很令人毛骨悚然,但我不知道为什么。

那么,作为设计结构及其相关函数或函数的人,何时应该收到指针?我什么时候应该收到价值?为什么?

换句话说,我的NewAuthor方法应何时返回&Author{ ... },何时返回Author{ ... }?什么时候我的函数应该将一个指向作者的指针作为一个参数,什么时候才能获得Author类型的值(副本)?

2 个答案:

答案 0 :(得分:3)

指针和值都存在权衡。

一般来说,指针将指向系统中的某些其他内存区域。无论是想要将指针传递给局部变量还是堆上某个位置的函数的堆栈。

func A() {
    i := 25
    B(&i) // A sets up stack frame to call B,
          // it copies the address of i so B can look it up later.
    // At this point, i is equal to 30
}
func B(i *int){
     // Here, i points to A's stack frame.
     // For this to execute, I look at my variable "i", 
     //   see the memory address it points to, then look at that to get the value of 25.
     // That address may be on another page of memory, 
     // causing me to have to look it up from main memory (which is slow).
     println(10 + (*i)) 

     // Since I have the address to A's local variable, I can modify it.
     *i = 30
}

每当我要查看指向的数据时,指针要求我不断地将它们取消引用。有时你不在乎。其他时候它很重要。这实际上取决于应用程序。

如果必须多次取消引用该指针(即:您传入一个数字以用于一堆不同的计算中),那么您将继续支付费用。

与使用值相比:

func A() {
    i := 25
    B(i) // A sets up the stack frame to call B, copying in the value 25
    // i is still 25, because A gave B a copy of the value, and not the address.
}
func B(i int){
     // Here, i is simply on the stack.  I don't have to do anything to use it.
     println(10 + i) 

     // Since i here is a value on B's stack, modifications are not visible outside B's scpe
     i = 30
}

由于无需解除引用,因此基本上可以自由使用局部变量。

如果这些值很大,则会发生传递值的下降,因为将数据复制到堆栈不是免费的。

对于int来说,它是一个清洗,因为指针的大小是“int”。对于结构或数组,您正在复制所有数据。

此外,堆栈上的大型对象可以使堆栈更大。 Go可以通过堆栈重新分配来处理这个问题,但在高性能方案中,它可能会对性能产生太大的影响。

还有一个数据安全方面(无法修改我通过值传递的内容),但我不认为这通常是大多数代码库中的问题。

基本上,如果您的问题已经可以通过ruby,python或其他没有值类型的语言解决,那么这些性能细微差别并不重要。

通常,在学习语言时,将结构作为指针传递通常会做“正确的事”。

对于所有其他类型或要保留为只读的内容,请传递值。

这条规则有例外,但最好是在需要时学习这些规则,而不是试图一次性重新定义你的世界。如果这是有道理的。

答案 1 :(得分:1)

您可以随时随地使用指针,有时您不想更改数据。它可能代表抽象数据,您不想明确地复制数据。只需按值传递,让编译器完成它的工作。