Pointers 这背后的动机是什么;模式;?

Pointers 这背后的动机是什么;模式;?,pointers,memory,go,Pointers,Memory,Go,当我看到如下代码时,我有点困惑: bigBox := &BigBox{} bigBox.BubbleGumsCount = 4 // correct... bigBox.SmallBox.AnyMagicItem = true // also correct 为什么,或者什么时候,我想做bigBox:=&bigBox{}而不是bigBox:=bigBox{}?在某种程度上它是否更有效 代码示例取自 样本2: package main import "fmt" ty

当我看到如下代码时,我有点困惑:

bigBox := &BigBox{}
bigBox.BubbleGumsCount = 4          // correct...
bigBox.SmallBox.AnyMagicItem = true // also correct
为什么,或者什么时候,我想做
bigBox:=&bigBox{}
而不是
bigBox:=bigBox{}
?在某种程度上它是否更有效

代码示例取自

样本2:

package main

import "fmt"

type Ints struct {
  x int
  y int
}

func build_struct() Ints {
  return Ints{0,0}
}

func build_pstruct() *Ints {
  return &Ints{0,0}
}

func main() {
  fmt.Println(build_struct())
  fmt.Println(build_pstruct())
}
示例3:(为什么在本例中使用&BigBox,而不是直接使用BigBox作为结构?)


是否有理由调用build_结构而不是build_结构变量?这不是我们使用GC的原因吗?

区别在于创建引用对象(带符号)和值对象(不带符号)

这里对值与引用类型的一般概念有一个很好的解释


这里有一些关于这些概念的讨论

bb:=&BigBox{}
创建一个结构,但将变量设置为指向它的指针。它与
bb:=new(BigBox)
相同。另一方面,
bb:=BigBox{}
使bb直接成为BigBox类型的变量。如果您想要一个指针(可能是因为您将通过指针使用数据),那么最好将bb设为指针,否则您将大量编写
&bb
。如果要直接将数据用作结构,则希望bb成为结构,否则将使用
*bb
解除引用

这不是问题的重点,但通常最好一次创建数据,而不是通过创建对象并随后更新它来增量创建数据

bb := &BigBox{
    BubbleGumsCount: 4,
    SmallBox: {
        AnyMagicItem: true,
    },
}

我找到了这种代码的一个动机:避免“意外复制结构”


如果使用结构变量保存新创建的结构:

bigBox := BigBox{}
您可能会像这样意外地复制结构

myBox := bigBox // Where you just want a refence of bigBox.
myBox.BubbleGumsCount = 4
changeBoxColorToRed(bigBox)
还是像这样

myBox := bigBox // Where you just want a refence of bigBox.
myBox.BubbleGumsCount = 4
changeBoxColorToRed(bigBox)
其中
changeBoxColorToRed

// It makes a copy of entire struct as parameter. 
func changeBoxColorToRed(box bigBox){
    // !!!! This function is buggy. It won't work as expected !!!
    // Please see the fix at the end.
    box.Color=red
}

但如果使用结构指针:

bigBox := &BigBox{}
将不会有复制

myBox := bigBox

将无法编译,使您有机会重新思考
changeBoxColorToRed
的设计。解决办法显而易见:

func changeBoxColorToRed(box *bigBox){
    box.Color=red
}

新版本的
changeBoxColorToRed
无法复制整个结构并正常工作。

通常
&BigBox{}
BigBox{}
之间没有区别。只要语义正确,Go编译器就可以自由地执行任何它喜欢的操作

func StructToStruct() {
    s := Foo{}
    StructFunction(&s)
}

func PointerToStruct() {
    p := &Foo{}
    StructFunction(p)
}

func StructToPointer() {
    s := Foo{}
    PointerFunction(&s)
}

func PointerToPointer() {
    p := &Foo{}
    PointerFunction(p)
}

//passed as a pointer, but used as struct
func StructFunction(f *Foo) {
    fmt.Println(*f)
}

func PointerFunction(f *Foo) {
    fmt.Println(f)
}
大会摘要:

  • StructToStruct
    :13行,无分配
  • PointerToStruct
    :16行,无分配
  • StructToPointer
    :20行,已分配堆
  • PointerToPointer
    :12行,已分配堆
有了完美的编译器,
*ToStruct
函数将与
*ToPointer
函数相同。Go的转义分析足以判断指针是否跨模块边界转义。哪种方法是最有效的,是编译器将采用的方法

如果您真的对微观优化感兴趣,请注意,当语法与语义一致时(struct用作struct,pointer用作指针),Go是最有效的。或者,您可以忘记它,按照使用它的方式声明变量,并且在大多数情况下您都是正确的


注意:如果
Foo
非常大,那么
PointerToStruct
将堆分配它。规范威胁说,即使
StructToStruct
也可以这样做,但我无法做到。这里的教训是编译器将执行它想要的任何操作。正如寄存器的细节被代码屏蔽一样,堆/堆栈的状态也是如此。不要更改代码,因为您认为您知道编译器将如何使用堆。

&
获取某个内容的地址。所以它的意思是“我想要一个指向的指针”,而不是“我想要一个的实例”。包含值的变量的大小取决于值的大小,可以是大的,也可以是小的。包含指针的变量的大小为8字节

以下是示例及其含义:

bigBox0 := &BigBox{} // bigBox0 is a pointer to an instance of BigBox{}
bigBox1 := BigBox{} // bigBox1 contains an instance of BigBox{}
bigBox2 := bigBox // bigBox2 is a copy of bigBox
bigBox3 := &bigBox // bigBox3 is a pointer to bigBox
bigBox4 := *bigBox3 // bigBox4 is a copy of bigBox, dereferenced from bigBox3 (a pointer)
你为什么想要一个指针

  • 防止在将大对象作为参数传递给函数时复制它
  • 您希望通过将值作为参数传递来修改该值
  • 为了使一个切片在数组的支持下保持小。[10] BigBox将占用“BigBox的大小”*10字节。[10] *BigBox将占用8个字节*10。调整大小后的片在达到其容量时必须创建更大的阵列。这意味着旧阵列的内存必须复制到新阵列
  • 你为什么不知道用什么指针


  • 如果一个物体很小,最好只是复制一个。特别是如果可以的话,那么在上述情况下,我们为什么要创建引用对象呢?我已经读了上一篇文章,但我仍然不清楚。不知道那个具体的例子。也许在他们的评论部分向作者提出了这个问题。因此,最终这只是个人偏好的问题,是将结构用作结构还是用作指针?不,这不是个人偏好:值和指针具有不同的语义和相当不同的性能含义。是的,我理解这一点。但是如果在我的整个程序中,我只有main:
    bb:=&BigBox{BubbleGumsCount:4};fmt.Println(bb.bubblegumscont),为什么我要将BigBox声明为指针而不是常规结构?哇,这真的很有意义!您使用的函数changeBoxColorToRed具有误导性,因为它不会更改颜色返回参数也是如此。例如,要回答问题中的示例2,请参见示例。注意struct返回,实际上分配了两个struct。指针返回指向在函数中分配的同一个指针…如果您理解指针是什么,就不会“意外复制结构”。有C/C++背景的人会知道这一点,或者任何有指针的语言。也许