如果运算符==和!=不是一个选项,我如何检查两个切片是否相等?

package main

import "fmt"

func main() {
    s1 := []int{1, 2}
    s2 := []int{1, 2}
    fmt.Println(s1 == s2)
}

它不使用:

无效的操作:s1 == s2 (slice只能与nil进行比较)


当前回答

如果您对编写测试感兴趣,那么github.com/stretchr/testify/assert就是您的好朋友。

在文件的最开始导入库:

import (
    "github.com/stretchr/testify/assert"
)

然后在测试中你要做:


func TestEquality_SomeSlice (t * testing.T) {
    a := []int{1, 2}
    b := []int{2, 1}
    assert.Equal(t, a, b)
}

提示的错误将是:

                Diff:
                --- Expected
                +++ Actual
                @@ -1,4 +1,4 @@
                 ([]int) (len=2) {
                + (int) 1,
                  (int) 2,
                - (int) 2,
                  (int) 1,
Test:           TestEquality_SomeSlice

其他回答

想到了一个妙招,想和大家分享一下。

如果你感兴趣的是两个切片是否相同(即它们在相同的数据区域中使用别名),而不仅仅是相等(一个切片的每个索引上的值等于另一个切片的相同索引上的值),那么你可以用以下方式有效地比较它们:

foo := []int{1,3,5,7,9,11,13,15,17,19}

// these two slices are exactly identical
subslice1 := foo[3:][:4]
subslice2 := foo[:7][3:]

slicesEqual := &subslice1[0]  == &subslice2[0]   && 
               len(subslice1) == len(subslice2)

对于这种比较有一些注意事项,特别是您不能以这种方式比较空切片,并且切片的容量不会进行比较,因此这种“同一性”属性仅在从切片中读取或对严格狭窄的子切片进行切片时才真正有用,因为任何增加切片的尝试都会受到切片容量的影响。不过,能够有效地声明“这两个巨大的内存块实际上是同一个块,是或不是”是非常有用的。

如果你有两个[]字节,使用bytes.Equal进行比较。Golang文档说:

Equal返回一个布尔值,报告a和b是否长度相同且包含相同的字节。nil参数相当于一个空切片。

用法:

package main

import (
    "fmt"
    "bytes"
)

func main() {
    a := []byte {1,2,3}
    b := []byte {1,2,3}
    c := []byte {1,2,2}

    fmt.Println(bytes.Equal(a, b))
    fmt.Println(bytes.Equal(a, c))
}

这将打印

true
false

现在,这里是https://github.com/google/go-cmp

是一种更强大、更安全的反映方式。DeepEqual用于比较两个值在语义上是否相等。

package main

import (
    "fmt"

    "github.com/google/go-cmp/cmp"
)

func main() {
    a := []byte{1, 2, 3}
    b := []byte{1, 2, 3}

    fmt.Println(cmp.Equal(a, b)) // true
}

这只是使用@VictorDeryagin的回答中给出的reflect.DeepEqual()的示例。

package main

import (
    "fmt"
    "reflect"
)

func main() {
    a := []int {4,5,6}
    b := []int {4,5,6}
    c := []int {4,5,6,7}

    fmt.Println(reflect.DeepEqual(a, b))
    fmt.Println(reflect.DeepEqual(a, c))

}

结果:

true
false

试试在围棋游乐场

你不能对切片使用==或!=,但如果你可以对元素使用==或!=,那么Go 1.18有一个新功能,可以轻松地比较两个切片。平等:

Equal报告两个切片是否相等:长度相同且所有元素相等。如果长度不同,Equal返回false。否则,元素按照递增的索引顺序进行比较,并且比较在第一个不相等的对处停止。浮点nan不被认为是相等的。

切片包的导入路径为golang.org/x/exp/slices。exp包中的代码是实验性的,还不稳定。它最终将被移到Go 1.19的标准库中。

尽管如此,你可以在Go 1.18(游乐场)中使用它

    sliceA := []int{1, 2}
    sliceB := []int{1, 2}
    equal := slices.Equal(sliceA, sliceB)
    fmt.Println(equal) // true

    type data struct {
        num   float64
        label string
    }

    sliceC := []data{{10.99, "toy"}, {500.49, "phone"}}
    sliceD := []data{{10.99, "toy"}, {200.0, "phone"}}
    equal = slices.Equal(sliceC, sliceD)
    fmt.Println(equal) // true

如果片的元素不允许==和!=,您可以使用片。EqualFunc并定义任何对元素类型有意义的比较器函数。