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)
}
大会摘要:
:13行,无分配StructToStruct
:16行,无分配PointerToStruct
:20行,已分配堆StructToPointer
:12行,已分配堆PointerToPointer
*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)
你为什么想要一个指针
bb:=&BigBox{BubbleGumsCount:4};fmt.Println(bb.bubblegumscont)代码>,为什么我要将BigBox声明为指针而不是常规结构?哇,这真的很有意义!您使用的函数changeBoxColorToRed具有误导性,因为它不会更改颜色返回参数也是如此。例如,要回答问题中的示例2,请参见示例。注意struct返回,实际上分配了两个struct。指针返回指向在函数中分配的同一个指针…如果您理解指针是什么,就不会“意外复制结构”。有C/C++背景的人会知道这一点,或者任何有指针的语言。也许