不同的指针是否相等?

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

Different pointers are equal?

问题

我正在尝试将一些二维平面上的点表示为整数对。我希望这些点是不可变的(按值传递),但每个点都有唯一的标识。为了实现这一点,我创建了一个包含两个整数和一个字符串指针的结构体。这个方法运行良好:

package main
import "fmt"
func main() {
    s1 := ""
    s2 := ""
    p := Point{1,2,&s1}
    p2 := Point{1,2,&s2}
    fmt.Println(p2==p) // 希望输出 false
}
type Point struct{X int; Y int; id *string}

输出结果为 false

由于字符串实际上没有被用于任何操作(我只关心判断两个点是否相同),似乎使用指向 struct{} 的指针作为唯一引用的规范解决方案会更好:

package main
import "fmt"
func main() {
    s1 := struct{}{}
    s2 := struct{}{}
    p := Point{1,2,&s1}
    p2 := Point{1,2,&s2}
    fmt.Println(p2==p) // 希望输出 false
}
type Point struct{X int; Y int; id *struct{}}

然而,现在两个指针是相等的:

输出结果为 true

为什么会这样?字符串也会发生这种情况吗?我应该使用 UUID 吗?

英文:

I'm trying to represent some points on a 2d plane as pairs of integers. I want the points to be immutable (pass-by-value), but also for each to have a unique identity. To accomplish this, I made a struct with two ints and a *string. This works fine:

package main
import "fmt"
func main() {
    s1 := ""
    s2 := ""
    p := Point{1,2,&s1}
    p2 := Point{1,2,&s2}
    fmt.Println(p2==p) // want false
}
type Point struct{X int; Y int; id *string}

<!

$ go run a.go
false

Since the string isn't actually used for anything (I only care about telling whether two points are the same), it seems like the canonical solution for making a unique reference like this would be to use a pointer to struct{} instead:

package main
import &quot;fmt&quot;
func main() {
    s1 := struct{}{}
    s2 := struct{}{}
    p := Point{1,2,&amp;s1}
    p2 := Point{1,2,&amp;s2}
    fmt.Println(p2==p) // want false
}
type Point struct{X int; Y int; id *struct{}}

However, now the two pointers are equal:

$ go run a.go
true

Why? Can this happen with strings as well? Should I use UUIDs instead?

答案1

得分: 7

空结构体struct{}{}是特殊的。

参见:http://golang.org/ref/spec#Size_and_alignment_guarantees,其中写道:

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

你可以简单地在其中添加一个字段来确保唯一性。例如:

package main

import "fmt"

type token struct{ bool }
type Point struct {
    X  int
    Y  int
    id *token
}

func main() {
    p := Point{1, 2, &token{}}
    p2 := Point{1, 2, &token{}}
    fmt.Println(p2 == p) // 期望输出为 false
}
英文:

The empty struct struct{}{} is special.

See: http://golang.org/ref/spec#Size_and_alignment_guarantees where it says:

> 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.

You can probably just put a field in there to get uniqueness. Something like:

package main

import &quot;fmt&quot;

type token struct{ bool }
type Point struct {
	X  int
	Y  int
	id *token
}

func main() {
	p := Point{1, 2, &amp;token{}}
	p2 := Point{1, 2, &amp;token{}}
	fmt.Println(p2 == p) // want false
}

答案2

得分: 2

为了区分两个不同的点,即使它们具有相同的坐标,可以使用地址。例如,

package main

import "fmt"

type Point struct {
    X int
    Y int
    p *Point
}

func NewPoint(x, y int) Point {
    p := Point{X: x, Y: y}
    p.p = &p
    return p
}

func main() {
    x, y := 1, 2
    p1 := NewPoint(x, y)
    p2 := NewPoint(x, y)
    fmt.Println(p1)
    fmt.Println(p2)
    fmt.Println(p1 == p1)
    fmt.Println(p1 == p2)
}

输出:

{1 2 0x10328000}
{1 2 0x10328020}
true
false
英文:

To distinguish between two different points, even if they have the same coordinates, use addresses. For example,

package main

import &quot;fmt&quot;

type Point struct {
	X int
	Y int
	p *Point
}

func NewPoint(x, y int) Point {
	p := Point{X: x, Y: y}
	p.p = &amp;p
	return p
}

func main() {
	x, y := 1, 2
	p1 := NewPoint(x, y)
	p2 := NewPoint(x, y)
	fmt.Println(p1)
	fmt.Println(p2)
	fmt.Println(p1 == p1)
	fmt.Println(p1 == p2)
}

Output:

{1 2 0x10328000}
{1 2 0x10328020}
true
false

huangapple
  • 本文由 发表于 2014年9月9日 07:17:59
  • 转载请务必保留本文链接:https://go.coder-hub.com/25734504.html
匿名

发表评论

匿名网友

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

确定