初始化结构体时,可以选择将其声明为指针或非指针类型。

huangapple go评论78阅读模式
英文:

Initializing a struct as a pointer or not

问题

这两种初始化Vertex结构体的方式有什么区别?

我知道第二种方式是使用指针进行分配,但在实践中我看不出这种解决方案有什么区别。

英文:
type Vertex struct {
	X, Y float64
}

func main() {
	v := Vertex{3, 4}
	fmt.Println(v)

	d := &Vertex{3, 4}
	fmt.Println(d)
}

http://play.golang.org/p/XluyUHL2y7

What's the difference between these two ways to initialize a Vertex struct?

I know that second one is allocation with pointer, but I can't see any difference of this solution in practice.

答案1

得分: 4

TL;DR 没有区别<sup>1</sup>。变量是分配在堆栈还是堆上取决于它的使用方式。

我对Go生成的汇编代码进行了深入研究,包括各种初始化和调用情况。在vb之间生成的汇编代码几乎相同。特别要注意的是,d并没有分配在堆栈上<sup>1</sup>。

决定变量是堆分配还是栈分配的因素是它的使用方式。将指针传递给一个只将参数作为值使用的函数不会强制将变量分配在堆上。但即使如此,也不能保证,规范允许任何Go编译器根据优化或代码生成的需要自由地在堆栈之间移动变量。Go 抽象了堆和栈,就像C/C++抽象了RAM和寄存器一样。

http://play.golang.org/p/vJQvWPTGeR

type Vertex struct {
	X, Y float64
}

func PrintPointer(v *Vertex) {
	fmt.Println(v)
}

func PrintValue(v *Vertex) {
	fmt.Println(*v)
}

func main() {
	a := Vertex{3, 4} // 未分配
	PrintValue(&amp;a)

	b := &amp;Vertex{3, 4} // 未分配
	PrintValue(b)

	c := Vertex{3, 4} // 已分配
	PrintPointer(&amp;c)

	d := &amp;Vertex{3, 4} // 已分配
	PrintPointer(d)
}

<sup>1</sup>: 严格来说不准确,但如果使用了fmt.Println(*d),则是正确的。我稍微作弊了一下,回答了我认为你想问的问题。

英文:

TL;DR There is no difference<sup>1</sup>. Whether a variable is allocated on the stack or heap depends on its usage.

I did a deep dive on the the assembly Go generates from various initialization and calling cases. The assembly generated between v and b is nearly the same. Of particular note, d is not allocated on the stack<sup>1</sup>.

What determines whether a variable is heap allocated or stack allocated is how it is used. Passing a passing a pointer into a function that only used the parameter as a value will not force a variable to be heap allocated. But even this isn't guaranteed, the spec allows any Go compiler to freely move variables between the stack an heap as needed for optimization or code generation. Go abstracts away Heap vs Stack just as C/C++ abstracts away RAM vs Register.

http://play.golang.org/p/vJQvWPTGeR

type Vertex struct {
	X, Y float64
}

func PrintPointer(v *Vertex) {
	fmt.Println(v)
}

func PrintValue(v *Vertex) {
	fmt.Println(*v)
}

func main() {
	a := Vertex{3, 4} // not allocated
	PrintValue(&amp;a)

	b := &amp;Vertex{3, 4} // not allocated
	PrintValue(b)

	c := Vertex{3, 4} // allocated
	PrintPointer(&amp;c)

	d := &amp;Vertex{3, 4} // allocated
	PrintPointer(d)
}

<sup>1</sup>: technically not true, but would be true if fmt.Println(*d) had been used instead. I cheated a little to answer the question I think you meant to ask.

答案2

得分: 3

在这两种情况下,都以相同的方式初始化了一个Vertex结构体。

第一个表达式返回一个已初始化的Vertex结构体的值。根据6g的对齐规则,这意味着你将得到16字节大小的Vertex结构体,因为每个float64类型的大小为8字节。
第二个表达式分配了足够的内存,足够存放16字节大小的数据,并将其用作Vertex结构体,然后进行初始化,并返回一个指针,这个指针的大小将根据你的架构是4字节还是8字节。

在实践中有一些区别。这两个值,即Vertex结构体和Vertex指针,的方法集可能不同。根据你需要多频繁地传递Vertex结构体,传递指针可能更高效,也可能不是更高效的。如果你将Vertex结构体传递给一个函数,函数会得到一个副本,你的Vertex结构体将永远不会被修改。如果你传递一个Vertex指针,底层的Vertex可能会被修改。这可能是你的意图,也可能不是你的意图 初始化结构体时,可以选择将其声明为指针或非指针类型。

英文:

In both cases, a Vertex struct is intialized in the same way.

The first expression returns value which is an initialized Vertex struct. With 6g's alignment rules, this means that you will get 8+8 = 16 bytes worth of Vertex struct, since every float64 is 8 bytes in size.
The second expression allocates memory, enough for 8+8 = 16 bytes, uses it as a Vertex struct, initializes it and returns a pointer, which will be 4 or 8 bytes in size, depending on your architecture.

There are a number of differences in practice. The method sets of these two values, the Vertex struct and the *Vertex pointer, may be different. Depending on how often you need to pass around the Vertex struct, it might or might not be more efficient to pass a pointer to it. If you pass a Vertex struct to a function, the function gets a copy and your Vertex struct will never be modified. If you pass a *Vertex, your underlying Vertex might be changed. This might or might not be your intention 初始化结构体时,可以选择将其声明为指针或非指针类型。

huangapple
  • 本文由 发表于 2013年10月17日 05:30:26
  • 转载请务必保留本文链接:https://go.coder-hub.com/19414267.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定