What golang compiler will do when fmt.Println()

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

What golang compiler will do when fmt.Println()

问题

我正在尝试理解如何在实现相同接口的两个对象之间检查它们是否相同。

以下是示例代码:

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) 
}

结果是:

not same
not same
same

a1 和 a2 不相同。

但是,如果取消注释第22行:

fmt.Println(&a, &b)

结果是:

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

有人能解释这里发生了什么吗?Golang 编译器进行了优化吗?

谢谢。

英文:

I'm trying to understand how to check if two objects are the same when they implement the same interface.

Here is the example code:

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

The result is:

not same
not same
same

a1 and a2 are not the same

But if uncomment the line#22

fmt.Println(&a, &b)

The result is:

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

Does anyone can figure out what happened here?
Does the Golang compiler optimize something?

Thanks

答案1

得分: 2

这似乎是一个更复杂的例子,类似于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{}),差异是由于编译器优化引起的。

英文:

This appears to be a more complicated example of https://github.com/golang/go/issues/8938.

The relevant parts of the Go spec are https://golang.org/ref/spec#Comparison_operators

> Pointers to distinct zero-size variables may or may not be equal.

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

> Two distinct zero-size variables may have the same address in memory.

Based on the title of the issue linked above (cmd/compile: optimisations change the behaviour of *struct{}), the difference is due to compiler optimizations.

答案2

得分: 0

这是预期的行为。背景是,== 是一个比较两个对象的的运算符。这被称为对象相等性。而比较它们的指针值或身份是不同的。请参考这个类似的帖子上的顶部答案。

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

当你询问 a1 == a2 时,你会得到 true,因为 a1a2 只是同一个结构体的不同实例。参考我上面链接的帖子,a1a2相等的,但它们不共享相同的身份。

最后,当你询问 a1 == a1 时,你是在询问同一个对象的同一个实例是否等于它自己,这当然是 true。在这种情况下,a1 既与 a1 相等又与 a1 具有相同的身份。

英文:

This is expected behavior. For background, == is an operator which compares the value of two objects. This is known as object equality. Comparing their pointer value, or their identity, is different. See the top answer on this similar post.

When you ask a1 == b1, you receive false because a1 is an instance of the a struct, whereas b1 is an instance of the b struct. Therefore, even though they implement the same interface, they are not == to each other. Consider your a struct and b struct where they had additional and different methods implemented in both (so a has an additional method foo() and b has an additional method bar()). Although a and b would implement the same interface, they would not be the same, nor would you expect or want them to be.

When you ask if a1 == a2, you receive true because a1 and a2 are just separate instances of the same struct. Referencing the post I linked above, a1 and a2 are equal, but do not share the same identity.

Finally, when you ask if a1 == a1, you are asking if the same instance of the same object is equal to itself, which of course is true. In this case, a1 shares both equality and identity with a1.

答案3

得分: 0

你应该使用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

只是Go语言编译器的优化,我猜测。

英文:

You should use reflect.DeepEqual to compare struct, slice and map.

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")
	}

}

The result is:

0x196a9c
not same

Using reflect.DeepEqual as below:

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))
}

The Result is:

0x196a9c
same
true

Just golang compiler optimization i guess.

huangapple
  • 本文由 发表于 2016年12月28日 16:11:11
  • 转载请务必保留本文链接:https://go.coder-hub.com/41357948.html
匿名

发表评论

匿名网友

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

确定