Go语言 检查两个切片是否相等

kuhbmx9i  于 2022-12-25  发布在  Go
关注(0)|答案(8)|浏览(322)

如果没有==!=运算符,如何检查两个切片是否相等?

package main

import "fmt"

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

这不与以下项一起编译:
无效操作:s1 == s2(切片只能与nil比较)

k75qkfdt

k75qkfdt1#

您应该使用reflect.DeepEqual()
DeepEqual是Go语言==运算符的递归松弛。
DeepEqual报告x和y是否“完全相等”,定义如下。如果出现以下情况之一,则两个相同类型的值完全相等。不同类型的值永远不会完全相等。
当数组值的对应元素完全相等时,数组值也完全相等。
如果结构值的相应字段(导出字段和未导出字段)完全相等,则结构值完全相等。
如果两者都为零,则函数值完全相等;否则它们并不完全相等。
如果界面价值持有深度相等的具体价值,那么界面价值就是深度相等的。
如果Map值是同一个Map对象,或者长度相同,并且对应的键(使用Go等式匹配)Map到深度相等的值,则Map值深度相等。
如果使用Go语言的==运算符,指针值相等,或者指针指向的值非常相等,那么指针值就是非常相等的。

当以下所有条件均为真时,切片值完全相等:它们都是nil或都是non-nil,它们具有相同的长度,并且它们要么指向相同基础数组的相同初始条目(即&x[0] == &y[0]),要么它们对应的元素(直到length)深度相等。注意,non-nil空切片和nil切片(例如,[]byte{}和[]byte(nil))并不深度相等。

其他值--数字、布尔值、字符串和通道--如果使用Go语言的==运算符,它们就完全相等。

eivnm1vs

eivnm1vs2#

您需要在切片中的每个元素上循环并测试。切片的相等性没有定义。但是,如果您比较[]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
}
q3qa4bjr

q3qa4bjr3#

这只是使用@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 Playground中试用

iszxjhcz

iszxjhcz4#

如果您有两个[]byte,请使用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
mw3dktmi

mw3dktmi5#

现在,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
}
2mbi3lxu

2mbi3lxu6#

我们不能将==!=与切片一起使用,但是如果可以将它们与元素一起使用,那么Go语言1.18有一个新函数slices.Equal,可以轻松地比较两个切片:
相等报告两个层切面是否相等:长度相同且所有元素相等。如果长度不同,则Equal返回false。否则,将按索引升序比较元素,并在第一个不相等的元素对处停止比较。浮点NaN不被视为相等。
slices包的导入路径为golang.org/x/exp/slicesexp包内的代码是 * 实验性的 *,还不稳定,最终会移入Go 1.19的标准库中。
尽管如此,您可以在Go语言1.18(playground)中使用它

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并定义任何对元素类型有意义的比较器函数。

monwx1rj

monwx1rj7#

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

nxowjjhe8#

想到了一个绝妙的小把戏我想和你分享一下。
如果您感兴趣的是了解两个切片是否相同(即它们为同一数据区域起别名),而不仅仅是相等(一个切片的每个索引处的值等于另一个切片的同一索引处的值),则可以通过以下方式有效地比较它们:

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)

这种比较有一些注意事项,特别是不能用这种方式比较空切片,而且切片的容量也不会比较,所以这个“identality”属性只有在从切片中阅读数据或者重新切片一个非常窄的子切片时才真正有用,因为任何增加切片的尝试都会受到切片容量的影响。“这两个巨大的内存块实际上是同一个块,是或否。”

相关问题