草庐IT

go - Go slice 的相等性(恒等式)

coder 2023-06-28 原文

我的问题与 this question 略有不同询问如何检查 Go slice 的相等性。

像这样article建议,Go slice 是一个,由三部分组成:指向数组的指针、段的长度及其容量(段的最大长度)。然后是否可以(便宜地)检查两个这样的 slice 是否相等,因为它们指向相同的底层数组并且具有相同的长度和容量值(最好不遍历两个 slice 检查各个元素的相等性)?似乎 == 运算符未在 slice 上定义。

当我实现一个内部使用 []uint64 来表示元素的位向量 (IntSet) 时出现了这个问题,我无意中实现了一个 方法 func (*IntSet) Equals(that *IntSet) bool 可以像s.Equals(s) 那样调用。

(看来我可以针对这种情况进行优化,如下所示,但问题仍然存在:

func (this *IntSet) Equals(that *IntSet) bool {
    if this == that { // use equality of pointers!
        return true
    }
// omitted for brevity 
}

最佳答案

使用第一个元素的地址

最简单的方法是简单地获取 slice 第一个元素的地址,然后比较它们(指针是 comparable )。我们可以简单地使用 address operator 来获取第一个元素的地址。 ,例如&s[0]。如果 slice 为空,则没有第一个元素,在这种情况下我们只检查两者是否为空。我们还必须比较 slice 的长度:

func identical(s1, s2 []int) bool {
    if len(s1) != len(s2) {
        return false
    }

    return len(s1) == 0 || &s1[0] == &s2[0]
}

我特意省略了容量比较,因为容量只有在 slice 被重新 slice 时才会起作用。

identical() 函数仅检查 slice 是否相同。 2 个不相同的 slice 可能相等(它们可能包含相同的元素),即使它们不相同。

测试它:

s := []int{1, 2, 3}
fmt.Println(identical(s, s))

s2 := []int{1, 2, 3}
fmt.Println(identical(s, s2))

输出是(在 Go Playground 上尝试):

true
false

使用reflect.SliceHeader

我们可以选择获取和使用包含指针、长度和容量的 slice 描述符。这是由 reflect.SliceHeader 建模的:

type SliceHeader struct {
        Data uintptr
        Len  int
        Cap  int
}

要获得一个reflect.SliceHeader,我们可以使用package unsafeunsafe.Pointer像这样输入:

var s []int = ... // s is a slice

// and h will be its descriptor, of type *reflect.SliceHeader
h := (*reflect.SliceHeader)(unsafe.Pointer(&s))

一个简单的比较器函数,用于检查 2 个 slice 是否相同,这意味着它们指向相同的后备数组并具有相同的长度(无论它们的容量如何):

func identical(s1, s2 []int) bool {
    h1 := (*reflect.SliceHeader)(unsafe.Pointer(&s1))
    h2 := (*reflect.SliceHeader)(unsafe.Pointer(&s2))

    return h1.Data == h2.Data && h1.Len == h2.Len
}

测试它:

s := []int{1, 2, 3}
fmt.Println(identical(s, s))

s2 := []int{1, 2, 3}
fmt.Println(identical(s, s2))

输出(在 Go Playground 上尝试):

true
false

关于go - Go slice 的相等性(恒等式),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53009686/

有关go - Go slice 的相等性(恒等式)的更多相关文章

  1. ruby - Ruby 的 Hash 在比较键时使用哪种相等性测试? - 2

    我有一个围绕一些对象的包装类,我想将这些对象用作散列中的键。包装对象和解包装对象应映射到相同的键。一个简单的例子是这样的:classAattr_reader:xdefinitialize(inner)@inner=innerenddefx;@inner.x;enddef==(other)@inner.x==other.xendenda=A.new(o)#oisjustanyobjectthatallowso.xb=A.new(o)h={a=>5}ph[a]#5ph[b]#nil,shouldbe5ph[o]#nil,shouldbe5我试过==、===、eq?并散列所有无济于事。

  2. ruby-on-rails - ActiveRecord 对象相等 - 2

    根据ActiveRecord::Base的文档:==(comparison_object)Returnstrueifcomparison_objectisthesameexactobject,orcomparison_objectisofthesametypeandselfhasanIDanditisequaltocomparison_object.id.Notethatnewrecordsaredifferentfromanyotherrecordbydefinition,unlesstheotherrecordisthereceiveritself.Besides,ifyoufet

  3. ruby-on-rails - Textmate 'Go to symbol' 相当于 Vim - 2

    在Railcasts上,我注意到一个非常有趣的功能“转到符号”窗口。它像Command-T一样工作,但显示当前文件中可用的类和方法。如何在vim中获取它? 最佳答案 尝试:helptags有各种程序和脚本可以生成标记文件。此外,标记文件格式非常简单,因此很容易将sed(1)或类似的脚本组合在一起,无论您使用何种语言,它们都可以生成标记文件。轻松获取标记文件(除了下载生成器之外)的关键在于格式化样式而不是实际解析语法。 关于ruby-on-rails-Textmate'Gotosymbol

  4. Ruby:检查所有数组元素是否相等 - 2

    我在使用Ruby代码时遇到了一些“问题”。我想检查数组的所有元素是否相等。例如,假设我有一个只有5的数组:arr=[5,5,5,5,5]我知道我可以做类似的事情arr[0]==arr[1]==arr[2]==arr[3]#==arr[4]==...但这对于巨大的数组来说是不可能的,而且在我看来也不是很像Ruby。我们可以通过做这样的事情来改进它:defall_equal?(arr)foriin0..(arr.size-2)ifarr[i]!=arr[i+1]thenreturnfalseendendtrueend但我也认为这很丑陋。那么是否有任何内置/更好/更短(更像Ruby风格)的方

  5. ruby - Ruby 中的 "=="是否总是值相等? - 2

    抱歉,如果重复(我没找到)这只是为了确认Ruby的运算符==始终执行相等比较。IE。a==b将a的值与b的值进行比较,而不是像Java那样比较它们是否指向内存中的同一个对象(对于后者,在Ruby中,您应该使用a.object_id==b.object_id).因此,在Ruby中将字符串值与==进行比较是安全的(而在Java中这样做并不安全)谢谢编辑:问题在于任何Ruby对象的默认==行为,因为它会误导Java-C-C++程序员假设a==b比较引用本身,而不是引用内容。无论如何,你可以检查这段代码,使用字符串one="hello"two="he"two编辑2。所以,在Ruby中,比较a=

  6. ruby - Ruby 的数组如何。比较元素是否相等? - 2

    下面是一些示例代码:classObjattr:c,truedef==thatp'=='that.c==self.cenddefthatp''that.cself.cenddefequal?thatp'equal?'that.c.equal?self.cenddefeql?thatp'eql?'that.c.eql?self.cendenda=Obj.newb=Obj.newa.c=1b.c=1p[a]|[b]它打印2个对象,但它应该打印1个对象。没有调用任何比较方法。阵列如何。|比较平等? 最佳答案 Array#|是使用散列实现的。

  7. ruby - 你如何覆盖 ruby​​ 大小写相等运算符? (===) - 2

    我有一个类,我想将它与case语句中的字符串和符号进行比较,所以我认为我只是为我的类重写了===()方法,所有这些都是黄金。但是我的===()方法在case语句中永远不会被调用。有什么想法吗?这是一些示例代码,以及在irbsession中发生的情况:classAdefinitialize(x)@x=x#notethisisn'tevenrequiredforthisexampleenddef===(other)puts"in==="returntrueendendirb(main):010:0>a=A.new("hi")=>#irb(main):011:0>caseairb(main)

  8. ruby-on-rails - 用于 Ruby 的 vim 中的全局 "Go to definition"? - 2

    自97年以来我一直在使用vi/vim进行各种快速编辑和管理任务,但最近才考虑使用它来替换Netbeans作为我选择的ruby​​编辑器。我发现一件事在Netbeans和Eclipse中非常有用的是Ctrl+Click“转到定义”功能,您可以在其中按住Ctrl键并单击一个类或方法,然后它将带您了解定义。现在,我玩过丰富的ctags和rails.vim,而且很接近,但没有雪茄。这就是我想要的:默认情况下在Netbeans和Eclipse中,您可以在本地rails中按住ctrl并单击本地方法或类项目,但你也可以ctrl+click定义在gems或用Ruby编写的系统库。以Netbeans为例

  9. ruby-on-rails - Rails 中确定两个(或更多)给定 URL(作为字符串或哈希选项)是否相等的最佳方法是什么? - 2

    我想要一个名为same_url的方法?如果传入的URL相等,它将返回true。传入的URL可能是参数选项散列或字符串。same_url?({:controller=>:foo,:action=>:bar},"http://www.example.com/foo/bar")#=>trueRails框架助手current_page?似乎是一个很好的起点,但我想传入任意数量的URL。作为一个额外的好处,如果可以传入要从比较中排除的参数的哈希值,那就太好了。因此方法调用可能如下所示:same_url?(projects_path(:page=>2),"projects?page=3",:exc

  10. ruby - Array#-(减法运算符)如何比较元素是否相等? - 2

    当我调用Array#-时,它似乎没有对我正在比较的字符串调用任何比较方法:classStringdef(v)puts"#{self}#{v}"super(v)enddef==(v)puts"#{self}==#{v}"super(v)enddef=~(v)puts"#{self}=~#{v}"super(v)enddef===(v)puts"#{self}==#{v}"super(v)enddefeql?(v)puts"#{self}.eql?#{v}"super(v)enddefequal?(v)puts"#{self}.equal?#{v}"super(v)enddefhash()

随机推荐