检查两个切片是否相等

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

package main


import "fmt"


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

它不使用:

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

183061 次浏览

您需要遍历切片中的每个元素并进行测试。切片的相等性没有定义。但是,如果比较类型为[]byte的值,则存在bytes.Equal函数。

func testEq(a, b []Type) bool {
if len(a) != len(b) {
return false
}
for i := range a {
if a[i] != b[i] {
return false
}
}
return true
}

你应该使用reflect.DeepEqual ()

DeepEqual是Go的==运算符的递归松弛。

DeepEqual报告x和y是否“深度相等”,定义为 遵循。类型相同的两个值深相等,如果其中一个为 以下情况适用。不同类型的值永远不会深 平等的。< / p >

数组值深度相等时,对应的元素为 深深平等。< / p >

Struct值深度相等,如果它们对应的字段,两者 输出和未输出,是完全相等的

函数值深度相等,如果两者都为nil;否则就不是 深深平等。< / p >

接口值深度相等,如果它们持有深度相等的具体 值。< / p >

如果映射值是相同的映射对象,或者如果它们是相同的映射对象,则映射值深度相等 具有相同的长度和相应的键(使用Go

)映射到深度相等的值 如果指针值使用Go的==相等,则它们是深度相等的

.

.

.

当以下所有条件都为真时,切片值深度相等 都是空值还是非空值,它们的长度相同 它们指向相同底层数组的相同初始项 (即&x[0] == &y[0])或它们对应的元素(直到 长度)是完全相等的。注意一个非空切片和一个空切片 切片(例如,[]byte{}和[]byte(nil))不是深度相等的

其他值-数字,bool,字符串和通道-是深的 如果它们相等,则使用Go的==运算符

这只是一个使用@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

去操场中试试

如果你有两个[]byte,使用字节。平等的比较它们。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

如果你对编写测试感兴趣,那么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

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

用于比较两个值在语义上是否相等,是reflect.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
}

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

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

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)

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

你不能对切片使用==!=,但如果你可以对元素使用它们,那么Go 1.18有一个新函数可以轻松地比较两个切片,slices.Equal:

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

slices包导入路径为golang.org/x/exp/slicesexp包中的代码是实验,还不稳定。它最终会被移到标准库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

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