为什么结构数组比较有不同的结果 [英] why struct arrays comparing has different result

查看:21
本文介绍了为什么结构数组比较有不同的结果的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我不知道为什么会发生下面的情况,而且我找不到相关的源代码.谁能给我解释一下?

I don't know why the below happens, and I can't find source code relative. Can anybody explain to me?

var s, ss struct{} // two empty structs
arr1 := [6]*struct{}{&s} // array with empty struct pointer
arr2 := [6]*struct{}{&ss} // array with empty struct pointer
fmt.Println(&s == &ss, arr1 == arr2)  // false, true

var l, ll struct{A int}{}
arr3 := [6]*struct{A int}{&l} // array with empty struct pointer
arr4 := [6]*struct{A int}{&ll} // array with empty struct pointer
fmt.Println(&l == &ll, arr3 == arr4)  // false, false

推荐答案

规范:比较运算符:

指针值具有可比性.如果两个指针指向同一个变量,或者两个指针的值都是 nil,则它们是相等的.指向不同零大小变量的指针可能相等,也可能不相等.

Pointer values are comparable. Two pointer values are equal if they point to the same variable or if both have value nil. Pointers to distinct zero-size variables may or may not be equal.

还有规范:尺寸和对齐保证:

如果结构或数组类型不包含大小大于零的字段(或元素),则其大小为零.两个不同的零大小变量可能在内存中具有相同的地址.

A struct or array type has size zero if it contains no fields (or elements, respectively) that have a size greater than zero. Two distinct zero-size variables may have the same address in memory.

sss 变量的大小为零,所以 &s&ss 是指向不同的零大小变量的指针,因此规范不保证它们的相等性.这意味着 &s == &ss 可能评估为 truefalse,你不能指望什么结果会是,这样做是错误的.

Size of the s and ss variables are zero, so &s and &ss are pointers to distinct zero-size variables, so the spec does not guarantee anything about their equality. What this means is that &s == &ss may evaluate to either true or false, you can't count on what the result will be, and it would be a mistake to do so.

不过,奇怪的是,在应用程序的单个运行时,一旦它们相等,一旦它们不相等.教训是永远不要依赖它.

Still, it is weird that during a single runtime of the app, once they are equal, and once they are not. Lesson is to not rely on it, ever.

可以通过查看逃逸分析来解释不同的行为.

The different behavior can be explained by looking at the escape analysis.

让我们将您的应用简化为:

Let's simplify your app to this:

var s, ss struct{}                   // two empty structs
arr1 := [6]*struct{}{&s}             // array with empty struct pointer
arr2 := [6]*struct{}{&ss}            // array with empty struct pointer
fmt.Println(&s == &ss, arr1 == arr2) // false, true

使用 go run -gcflags '-m' play.go 运行转义分析给出:

Running the escape analysis with go run -gcflags '-m' play.go gives:

./play.go:13:17: &s == &ss escapes to heap
./play.go:13:30: arr1 == arr2 escapes to heap
./play.go:11:23: main &s does not escape
./play.go:12:23: main &ss does not escape
./play.go:13:14: main &s does not escape
./play.go:13:20: main &ss does not escape
./play.go:13:13: main ... argument does not escape
false true

&s&ss 不会转义(因为它们不会传递给 fmt.Println(),只有结果&s == &ss).

&s and &ss do not escape (as they are not passed to fmt.Println(), only the result of &s == &ss).

如果我们在上面简化的应用程序中添加一行:

If we add a single line to the above simplified app:

var s, ss struct{}                   // two empty structs
arr1 := [6]*struct{}{&s}             // array with empty struct pointer
arr2 := [6]*struct{}{&ss}            // array with empty struct pointer
fmt.Println(&s == &ss, arr1 == arr2) // true, true

fmt.Printf("%p %p\n", &s, &ss) // true, true

运行逃逸分析现在给出:

Running escape analysis now gives:

./play.go:13:17: &s == &ss escapes to heap
./play.go:13:30: arr1 == arr2 escapes to heap
./play.go:15:24: &s escapes to heap
./play.go:15:24: &s escapes to heap
./play.go:10:6: moved to heap: s
./play.go:15:28: &ss escapes to heap
./play.go:15:28: &ss escapes to heap
./play.go:10:9: moved to heap: ss
./play.go:11:23: main &s does not escape
./play.go:12:23: main &ss does not escape
./play.go:13:14: main &s does not escape
./play.go:13:20: main &ss does not escape
./play.go:13:13: main ... argument does not escape
./play.go:15:12: main ... argument does not escape
true true

行为改变了:我们现在看到 true true 输出(在 去游乐场).

The behavior changed: we now see true true output (try it on the Go Playground).

行为改变的原因是因为 &s&ss 转义到堆:它们被直接传递给 fmt.Println(),所以编译器改变了它们的存储方式(位置),因此,它们的地址也改变了.

The reason for the changed behavior is because &s and &ss escape to heap: they are directly passed to fmt.Println(), so the compiler changed how (where) they are stored, and with that, so did their address.

查看相关/可能重复:Golang 切片地址空结构

这篇关于为什么结构数组比较有不同的结果的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆