Go 语言中那些对象比较方式
在 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 则不然。
- 点赞
- 收藏
- 关注作者
评论(0)