【问题标题】:What golang compiler will do when fmt.Println()fmt.Println()时golang编译器会做什么
【发布时间】:2016-12-28 08:11:11
【问题描述】:

我试图了解如何在两个对象实现相同的接口时检查它们是否相同。

示例代码如下:

package main

import (
    "fmt"
)

type shout interface {
    echo()
}

type a struct {}
func (*a) echo () {
    fmt.Println("a")
}

type b struct {}
func (*b) echo () {
    fmt.Println("b")
}

func compare(a, b shout) {
    //fmt.Println(&a, &b)
    if a == b {
        fmt.Println("same")
    } else {
        fmt.Println("not same")
    }
}

func main() {
    a1 := &a{}
    b1 := &b{}
    a2 := &a{}
    a1.echo()
    b1.echo()
    compare(a1, b1)
    compare(a1, a2)
    compare(a1, a1) 
}

https://play.golang.org/p/qo9XnbthMw

结果是:

not same
not same
same

a1和a2不一样

但是如果取消注释 #22 行

fmt.Println(&a, &b)

结果是:

0x1040a120 0x1040a128
not same
0x1040a140 0x1040a148
same
0x1040a158 0x1040a160
same

有谁知道这里发生了什么? Golang 编译器是否优化了某些东西?

谢谢

【问题讨论】:

  • 有或没有第22行,结果相同
  • 对不起,我已经更新了代码
  • 添加``` a1.echo() b1.echo() ``` 结果不一样
  • 我会在go-nuts 上发帖。在我看来,优化过程中发生了一些事情。
  • @sounder 在我更新此代码后你有什么想法吗?

标签: go interface


【解决方案1】:

这似乎是一个更复杂的 https://github.com/golang/go/issues/8938 示例。

Go 规范的相关部分是https://golang.org/ref/spec#Comparison_operators

指向不同的零大小变量的指针可能相等,也可能不相等。

https://golang.org/ref/spec#Size_and_alignment_guarantees

两个不同的零大小变量在内存中可能具有相同的地址。

根据上面链接的问题标题 (cmd/compile: optimisations change the behaviour of *struct{}),差异是由于编译器优化造成的。

【讨论】:

    【解决方案2】:

    这是预期的行为。对于背景,== 是一个比较两个对象的 value 的运算符。这称为对象相等。比较它们的指针值或它们的标识是不同的。请参阅this similar post 上的最佳答案。

    当您询问a1 == b1 时,您会收到false,因为a1a 结构的一个实例,而b1b 结构的一个实例。因此,即使它们实现了相同的接口,它们也不是== 彼此。考虑您的 a 结构和 b 结构,它们在两者中都实现了其他不同的方法(所以a 有一个额外的方法foo()b 有一个额外的方法bar())。尽管ab 会实现相同的接口,但它们不会相同,您也不会期望或希望它们相同。

    当您询问是否为 a1 == a2 时,您会得到 true,因为 a1a2 只是同一结构的不同实例。参考我上面链接的帖子,a1a2 相等,但不具有相同的身份。

    最后,当你问a1 == a1 时,你问的是同一个对象的同一个实例是否等于它自己,这当然是正确的。在这种情况下,a1a1 共享平等和身份。

    【讨论】:

    • 感谢您的解释。另一个我不明白的问题是为什么 fmt.Println() 会改变 if 语句的结果?
    【解决方案3】:

    您应该使用reflect.DeepEqual 来比较结构、切片和映射。

    package main
    
    import (
        "fmt"
    )
    
    type a struct{}
    
    func main() {
        a1 := &a{}
        a2 := &a{}
    
        fmt.Printf("%p\n", a1)
    
        if a1 == a2 {
            fmt.Println("same")
        } else {
            fmt.Println("not same")
        }
    
    }
    

    结果是:

    0x196a9c
    not same
    

    如下使用reflect.DeepEqual

    package main
    
    import (
        "fmt"
        "reflect"
    )
    
    type a struct{}
    
    func main() {
        a1 := &a{}
        a2 := &a{}
    
        fmt.Printf("%p\n", a1)
    
        if a1 == a2 {
            fmt.Println("same")
        } else {
            fmt.Println("not same")
        }
    
        fmt.Println(reflect.DeepEqual(a1, a2))
    }
    

    结果是:

    0x196a9c
    same
    true
    

    我猜只是 golang 编译器优化。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-03-01
      • 2011-11-27
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多