【问题标题】:How can I compare pointers in Go?如何比较 Go 中的指针?
【发布时间】:2017-11-19 15:14:50
【问题描述】:

我正在构建一些测试代码,并尝试将指针与<> 运算符进行比较。我的目标是将元素排列成一个平衡的树结构(由我实现)。为此,我需要快速、通用的比较。遵循古老的 C/C++ 习惯,我目前的想法是(...在撰写本文时)通过指针地址来比较它们。

但是,正如我发现的那样,它不起作用。来源

if (&(a.val) < &(b.val)) {

给出编译错误

./pointer.go:40: 无效操作: &a.val

ab 是带有 val 作为(安全)指针成员的结构。

是否可以在 go 中比较安全指针?怎么样?

是否保证指针的顺序保持不变? (例如,我可以想象一些 GC 诡计也会对数据进行重新排序。)

【问题讨论】:

  • Go 中没有指针运算。指针a小于指针b是什么意思?它有什么可能的信息表明一个内存地址小于另一个?
  • 是的,您可以将地址作为数字或十六进制字符串获取,这不是问题。就是比较指针值本身没有意义。
  • 当你得到的答案几乎是随机的时,你为什么要关心两个值的顺序?如果没有指针运算,指针指向的特定地址的信息是没有意义的。在 C(我假设是 C++)中,只有当两个指针指向同一个数组时才能比较指针(指针之间的所有其他比较都是未定义的)。
  • 在 C++ 中,如果 ab 是指针,那么 if (a-&gt;val &lt; b-&gt;val) { ... } 在 Go 中简单地转换为 if (a.val &lt; b.val) { ... }
  • @kriss 我实现了一个通用的 AVL 树,我想要这个作为默认比较函数。我坚持(来自 C++)比较指针会很有用。我当时不知道分配的内存地址可以在 Go 中改变。后来我知道了,我使用 C++ 抽象类的等价物来实现它。我从一开始就不喜欢默认的 go 库,尤其是它的哈希实现,并且它被硬连接到语言语法中,因为我认为它是 VLQ。由于这些原因,后来我不再使用 Go。

标签: pointers go comparison


【解决方案1】:

是否保证指针的顺序保持不变? (为了 例如,我可以想象一些 GC 诡计也会对数据进行重新排序。)

在回答您的这部分问题时,它看起来不像。请参阅下面的 pkg unsafe 链接。

如果要指针的内存地址,试试不安全的包:

https://golang.org/pkg/unsafe/#Pointer

package main

import (
    "fmt"
    "unsafe"
)

func main() {
    var a,b int
    var pa,pb *int
    pa = &a
    pb = &b

    //var c int
    //pa = &c

    if uintptr(unsafe.Pointer(pa)) < uintptr(unsafe.Pointer(pb)) {
      fmt.Printf("a:%p > b:%p",pa,pb)   
    } else {
      fmt.Printf("b:%p > a:%p",pb,pa)
    }

}

这将让您获得任意指针类型,然后是该指针的 当前 内存地址(就像 printf 一样)。但是请注意那里的警告,您不能依赖此地址:

将指针转换为 uintptr 会产生 指向的值,作为整数。这种 uintptr 的通常用途是 打印它。将 uintptr 转换回指针在 一般的。 uintptr 是整数,而不是引用。转换一个 指向 uintptr 的指针创建一个没有指针的整数值 语义。即使 uintptr 持有某个对象的地址, 垃圾收集器不会更新该 uintptr 的值,如果对象 移动,uintptr 也不会阻止对象被回收。

这会绕过 Go 类型系统和内存安全性,因此不安全,您可能不想这样做,除非您只是在试验。我想不出在测试中这样做的理由,但是如果您想确保阅读整个文档并非常确定您知道您正在做的事情将按您的预期工作。

【讨论】:

  • 我不推荐 unsafe :) 我认为有时值得解释一下为什么它是不安全的,以及如何做到这一点,这样人们就可以做出明智的决定......也许还能学到一点关于 Go 内存模型。
猜你喜欢
  • 2016-03-20
  • 2012-02-23
  • 1970-01-01
  • 2017-01-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多