Go 语言中那些对象比较方式

举报
宇宙之一粟 发表于 2022/04/15 00:25:29 2022/04/15
【摘要】 在 Go 中有不同的方法可以比较对象,但各有千秋。接下来,就让我们一起来看看这些对象比较的方式吧。 操作符 == 和 !=相等运算符是 Go 中比较事物的最简单且通常最有效的方法,但它仅适用于基本方式:使用 == 您可以比较基本类型,如 int 和 string,以及其中包含可以使用 == 进行比较的元素的数组和结构。尤其注意的是,它不适用于切片或映射。切片和映射只能与 nil 进行比较。p...

在 Go 中有不同的方法可以比较对象,但各有千秋。接下来,就让我们一起来看看这些对象比较的方式吧。

操作符 == 和 !=

相等运算符是 Go 中比较事物的最简单且通常最有效的方法,但它仅适用于基本方式:使用 == 您可以比较基本类型,如 int 和 string,以及其中包含可以使用 == 进行比较的元素的数组和结构。

尤其注意的是,它不适用于切片或映射。切片和映射只能与 nil 进行比较。

package main

import "fmt"

type compareStruct1 struct {
	A int
	B string
	C [5]int
}

func main() {

	a := "Hello"
	b := "Hello"
	fmt.Println("a == b is", a == b)

	s1 := compareStruct1{}
	s2 := compareStruct1{}
	fmt.Println("s1 == s2 is", s1 == s2)
}

结果:

a == b is true
s1 == s2 is true

一旦您向结构中添加了无法与 == 比较的属性,您就需要另一种比较方式:/

package main

import "fmt"

type compareStruct2 struct {
	A int
	B string
	C []int // changed type of C from array to slice
}

func main() {
	s1 := compareStruct2{}
	s2 := compareStruct2{}
        
	fmt.Println(s1 == s2)
}

结果为:

invalid operation: s1 == s2 (struct containing []int cannot be compared)

如果此时,还想进行比较,就需要编写专门的比较程序.

编写专门的代码

如果性能很重要,并且您需要比较稍微复杂的类型,那么最好的选择可能是手动比较:

package main

import "fmt"

type compareStruct struct {
	A int
	B string
	C []int
}

func (s *compareStruct) Equals(s2 *compareStruct) bool {
	if s.A != s2.A || s.B != s2.B || len(s.C) != len(s2.C) {
		return false
	}

	for i := 0; i < len(s.C); i++ {
		if s.C[i] != s2.C[i] {
			return false
		}
	}

	return true
}

func main() {
	s1 := compareStruct{}
	s2 := compareStruct{}

	fmt.Println(s1.Equals(&s2))
}

结果:true

reflect.DeepEqual

DeepEqual 是 Go 中最通用的比较事物的方法,它可以处理大部分事物。这是问题所在:

var (
    c1 = compareStruct{
        A: 1,
        B: "hello",
        C: []int{1, 2, 3},
    }
    c2 = compareStruct{
        A: 1,
        B: "hello",
        C: []int{1, 2, 3},
    }
)

func BenchmarkManual(b *testing.B) {
    for i := 0; i < b.N; i++ {
        c1.Equals(&c2)
    }
}

func BenchmarkDeepEqual(b *testing.B) {
    for i := 0; i < b.N; i++ {
        reflect.DeepEqual(c1, c2)
    }
}
BenchmarkManual-8 217182776 5.51 ns/op 0 B/op 0 allocs/op
BenchmarkDeepEqual-8 2175002 559 ns/op 144 B/op 8 allocs/op

在这个例子中,DeepEqual 比编写手动代码来比较该结构慢 100 倍。

请注意,DeepEqual 也会比较结构中未导出(小写)的字段。此外,即使它们是具有相同字段和值的两个不同结构,也永远不会认为两种不同类型是完全相等的。

不能比较类型

有些类型无法比较,甚至被认为是不相等的,例如具有 NaN 值或 func 类型的浮点变量。例如,如果您在结构中有这样的字段,则该结构不会是 DeepEqual 自身:

func TestF(t *testing.T) {
	x := math.NaN
	fmt.Println(reflect.DeepEqual(x, x))         // false
	fmt.Println(reflect.DeepEqual(TestF, TestF)) // false
}

bytes.Equal

bytes.Equal 是一种比较字节切片的特殊方法。它比简单地用 for 循环比较两个切片要快得多。

值得注意的是, bytes.Equal 函数认为空切片和 nil 切片是相等的,而 reflect.DeepEqual 则不然。

【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。