英文:
Why are these golang pointers not equal?
问题
在下面的示例中,我检查了两个指针的相等性:
- 这两个指针指向相同的地址
- 它们不是同一个指针
如何检查两个指针是否指向相同的地址?我不想检查两个指针的内容是否相等。
package main
import (
"fmt"
)
type Map struct {}
type Fragment struct {
Map *Map
}
func (m1 Map) NewFragment() (f Fragment) {
f.Map = &m1
return
}
var m Map = Map {}
func main() {
f := m.NewFragment()
fmt.Println(f.Map == &m) // false
fmt.Println(*f.Map == m) // true
}
英文:
In the example below I check the equality of two pointers
- The pointers are pointing to the same address
- They are not the same pointer
How do I check if two pointers are pointing to the same address? I do not want to check if the contents of both pointers are equal.
package main
import (
"fmt"
)
type Map struct {}
type Fragment struct {
Map *Map
}
func (m1 Map) NewFragment() (f Fragment) {
f.Map = &m1
return
}
var m Map = Map {}
func main() {
f := m.NewFragment()
fmt.Println(f.Map == &m) // false
fmt.Println(*f.Map == m) // true
}
答案1
得分: 6
正如JimB所回答的,你可以使用==
来比较指针。这个程序表现出这种行为的原因是因为当你调用NewFragment
方法时,接收器会被复制一份。在这种情况下,这意味着f.Map = &m1
这一行是取的副本的地址,而不是原始对象的地址。因此,指针是不同的(f.Map != &m
),而值是相同的(*f.Map == m
)。
英文:
As JimB answered, you can use ==
to compare pointers. The reason this program behaves that way is because when you call the NewFragment
method, a copy is made of the receiver. In this case, that means the line f.Map = &m1
is taking the address of the copy, not the original object. Therefore, the pointers are different (f.Map != &m
), and the values are the same (*f.Map == m
).
答案2
得分: 4
指针比较
> 相等运算符 == 和 != 适用于可比较的操作数。
> 指针值是可比较的。如果两个指针值指向同一个变量,或者都为 nil,则它们相等。
以下是一个有效的代码示例:
func main() {
s := struct{}{}
p1 := &s
p2 := &s
fmt.Println(p1 == p2)
fmt.Printf("%p, %p", p1, p2)
}
指针接收器
你的代码有一个重要的错误,实际上导致了你描述的行为。方法可以使用 值接收器 func (s SomeObj) DoSomething(){}
或 指针接收器 func (s *SomeObj) DoSomething(){}
声明。如果使用值接收器声明方法(就像你做的那样),你将得到对象的副本,但如果使用指针接收器声明方法(就像你应该做的那样),你将得到指向对象本身的指针。
你的代码只缺少一个星号:
type Map struct{}
type Fragment struct {
Map *Map
}
func (m1 *Map) NewFragment() (f Fragment) { // 注意,这是一个指针接收器
f.Map = m1
return
}
var m Map = Map{}
func main() {
f := m.NewFragment()
fmt.Println(f.Map == &m) // true
fmt.Println(*f.Map == m) // true
fmt.Printf("%p, %p", f.Map, &m)
}
结论
指针比较是检查是否为相同指针(身份)的操作。因此,如果你仔细观察你的代码,你会发现你的代码和我上面给出的示例具有相同的含义。
Playgrounds:
https://play.golang.org/p/GgTOEgvWA9
https://play.golang.org/p/kFxpu-8TDT
英文:
Pointers comparison
> The equality operators == and != apply to operands that are comparable.
> Pointer values are comparable. Two pointer values are equal if they point to the same variable or if both have value nil.
This is a valid code:
func main() {
s := struct{}{}
p1 := &s
p2 := &s
fmt.Println(p1 == p2)
fmt.Printf("%p, %p", p1, p2)
}
Pointer receivers
Your code has a significant mistake which actually caused the behavior you described. Method could be declared with value receiver func (s SomeObj) DoSomething(){}
and with pointer receiver func (s *SomeObj) DoSomething(){}
. If a method declared with value receiver (like you did) you will obtain a copy of the object but if you declare a method with pointer receiver (like you should do) you will obtain a pointer to the object itself.
Your code lacks only one asterisk:
type Map struct{}
type Fragment struct {
Map *Map
}
func (m1 *Map) NewFragment() (f Fragment) { // Note, this is a pointer receiver
f.Map = m1
return
}
var m Map = Map{}
func main() {
f := m.NewFragment()
fmt.Println(f.Map == &m) // true
fmt.Println(*f.Map == m) // true
fmt.Printf("%p, %p", f.Map, &m)
}
Conclusion
Pointer comparison is check whether it is the same pointer (identity). So if you look closer at your code you will see that your code and my example located above have the same meaning.
Playgounds:
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论