dongwa3808 2018-09-20 08:50
浏览 77
已采纳

为什么比较结构数组有不同的结果

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
  • 写回答

1条回答 默认 最新

  • dongmei8209 2018-09-20 08:59
    关注

    Spec: Comparison operators:

    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.

    And also Spec: Size and alignment guarantees:

    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.

    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
    

    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 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
    ", &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
    

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

    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.

    See related / possible duplicate: Golang Address of Slices of Empty Structs

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥15 求差集那个函数有问题,有无佬可以解决
  • ¥15 【提问】基于Invest的水源涵养
  • ¥20 微信网友居然可以通过vx号找到我绑的手机号
  • ¥15 寻一个支付宝扫码远程授权登录的软件助手app
  • ¥15 解riccati方程组
  • ¥15 display:none;样式在嵌套结构中的已设置了display样式的元素上不起作用?
  • ¥15 使用rabbitMQ 消息队列作为url源进行多线程爬取时,总有几个url没有处理的问题。
  • ¥15 Ubuntu在安装序列比对软件STAR时出现报错如何解决
  • ¥50 树莓派安卓APK系统签名
  • ¥65 汇编语言除法溢出问题