Pointers 在设计和编写库时,什么时候应该使用指针作为参数,什么时候不应该?

Pointers 在设计和编写库时,什么时候应该使用指针作为参数,什么时候不应该?,pointers,go,Pointers,Go,对不起,如果我的问题看起来很愚蠢。我的背景是PHP、Ruby、Python、Lua和类似的语言,我对现实场景中的指针一无所知 从我在互联网上读到的以及我在一个问题()中得到的回答来看,我明白: 复制大数据时应使用指针。接收并访问它,而不是获取整个对象层次结构 当结构上有一个修改它的函数时,必须使用指针 因此,指针似乎是一件很棒的事情:我应该总是把它们作为函数参数,因为它们非常轻量级,如果我最终不需要修改结构上的任何东西,那也没关系 然而,从直觉上看,我能感觉到这听起来很恐怖,但我不知道为什么

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

从我在互联网上读到的以及我在一个问题()中得到的回答来看,我明白:

  • 复制大数据时应使用指针。接收并访问它,而不是获取整个对象层次结构
  • 当结构上有一个修改它的函数时,必须使用指针
因此,指针似乎是一件很棒的事情:我应该总是把它们作为函数参数,因为它们非常轻量级,如果我最终不需要修改结构上的任何东西,那也没关系

然而,从直觉上看,我能感觉到这听起来很恐怖,但我不知道为什么

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


换句话说,我的
NewAuthor
方法什么时候应该返回
&Author{…}
,什么时候应该返回
Author{…}
?我的函数什么时候应该获取指向作者的指针作为参数,什么时候应该只获取类型
author
的值(副本)?

只要你想在任何地方使用指针,有时你不想更改数据。它可能代表抽象数据,您不希望显式复制数据。只需传递值,让编译器完成它的工作。

指针和值都有折衷

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

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或其他没有值类型的语言解决了,那么这些性能细微差别就无关紧要了

一般来说,在学习语言时,将结构作为指针传递通常是“正确的事情”

对于所有其他类型或要保持为只读的对象,传递值


这条规则也有例外,但最好是在需要时学习,而不是试图一下子重新定义你的世界。如果这有意义的话。

related:在Go中,如果我希望我的类型的实例是不可变的,我只会选择指针上的值。在我看来,指针几乎总是更好的,而不仅仅是在围棋中。我来自类似的背景(Python,它没有明确的指针),并且已经接受了@evanmcdonnal给出的相同建议。如果没有显式不可变的类,则应通过指针传递。此外,如果不可变值较大,则仍要传递指针,并且仅在接口中提供getter。