Golang

关注公众号 jb51net

关闭
首页 > 脚本专栏 > Golang > Golang struct slice map

Golang判断struct/slice/map是否相等以及对比的方法总结

作者:1个俗人

平时开发中对比两个struct或者map、slice是否相等是经常遇到的,有很多对比的方式,比如==,reflect.DeepEqual(),cmp.Equal()等也是经常容易混淆的,这么多种对比方式,适用场景和优缺点都有哪些呢?今天我们来具体总结一下,感兴趣的小伙伴们可以参考借鉴

前言

平时开发中对比两个struct或者mapslice是否相等是经常遇到的,有很多对比的方式,比如==reflect.DeepEqual()cmp.Equal()等也是经常容易混淆的,这么多种对比方式,适用场景和优缺点都有哪些呢?为什么可以用==,有的却不可以呢?问题多多,今天我们来具体总结一下,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。

== 的对比方式

== 适用的类型

相信==判等操作,大家每天都在用。golang中对==的处理有一些细节的地方需要特别注意,==操作最重要的一个前提是:两个操作数类型必须相同!如果类型不同,那么编译时就会报错。

示例代码:

package main

import "fmt"

func main() {
    var a int32
    var b int64
    // 编译错误:invalid operation a == b (mismatched types int32 and int64)
    fmt.Println(a == b)
}

经常见到使用==的类型一般是:string,int等基本类型。struct有时候可以用有时候不可以。slicemap使用 ==会报错。

slice和map使用 ==

因为slice和map不止是需要比较值,还需要比较len和cap,层级比较深的话还需要递归比较,不是简单的==就可以比较的,所以他们各自之间是不可以直接用==比较的,slice和map只能和nil使用==。

s1 := []int64{1, 3}
s2 := []int64{1, 2}
if s1 == nil {} //编辑器不会提示报错
if s1 == s2 {} //编辑器会提示报错

channel使用 ==

channel是引用类型,对比的是存储数据的地址。channel是可以使用==的,只要类型一样就可以。

ch1 := make(chan int, 1)
ch2 := ch1
if cha2 == cha1{fmt.Println("true")} // true

struct结构体使用==

结构体的定义只是一种内存布局的描述,只有当结构体实例化时,才会真正地分配内存。

实例化就是根据结构体定义的格式创建一份与格式一致的内存区域,结构体实例与实例间的

内存是完全独立的。对结构体进行&取地址操作时,视为对该类型进行一次 new 的实例化操作

因此:go中的结构体: v = Struct {}, v = &Struct{} 这个两种写法是等价的。

示例代码:

package main

import (
    "fmt" 
)
type User struct {
    Name string
    Age  int64
}
type People struct {
    Name string
    Hobby []string
}

func main() {
        p1 := People{Name: "test", Hobby: []string{"唱", "跳"}}
        p2 := People{Name: "test", Hobby: []string{"唱", "跳"}}

        u1 := User{Name: "test", Age:18}
		u2 := User{Name: "test", Age:18}

        if p1 == p2 {
            fmt.Println("p1 ==  p2") //报错
        }

    	if u1 == u2 {
            fmt.Println("u1 ==  u2")
        }
    }

reflect.DeepEqual() 和cmp.Equal()

reflect.DeepEqual()

reflect包提供的深度对比(递归)的方法,适用于go中的slice,map,struct,function的对比。

对比规则

通过以上规则可以看到,reflect.DeepEqual是可以比较struct的,同时也可以用来比较slicemap

示例代码:

package main

import (
    "fmt"
    "reflect"
)

type People struct {
    Name string
    Hobby []string
}

func main() {
        p1 := People{Name: "test", Hobby: []string{"唱", "跳"}}
        p2 := People{Name: "test", Hobby: []string{"唱", "跳"}}
        if reflect.DeepEqual(p1, p2) {
            fmt.Println("struct true")
        }
        mp1 := map[int]int{1: 1, 2: 2}
	    mp2 := map[int]int{1: 1, 2: 2}
        if ok := reflect.DeepEqual(mp1, mp2);ok {
			fmt.Println("mp1 == mp2!")
	    } else {
			fmt.Println("mp1 != mp2!")
	    }
    }

cmp.Equal()

go-cmp是 Google 开源的比较库,它提供了丰富的选项。

对比规则

示例代码:

package main

import (
  "fmt"

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

type Contact struct {
  Phone string
  Email string
}

type User struct {
  Name    string
  Age     int
  Contact *Contact
}

func main() {
  u1 := User{Name: "test", Age: 18}
  u2 := User{Name: "test", Age: 18}

  fmt.Println("u1 == u2?", u1 == u2)  //true
  fmt.Println("u1 equals u2?", cmp.Equal(u1, u2)) //true

  c1 := &Contact{Phone: "123456789", Email: "dj@example.com"}
  c2 := &Contact{Phone: "123456789", Email: "dj@example.com"}

  u1.Contact = c1
  u2.Contact = c1
  fmt.Println("u1 == u2 with same pointer?", u1 == u2) //true
  fmt.Println("u1 equals u2 with same pointer?", cmp.Equal(u1, u2)) //true

  u2.Contact = c2
  fmt.Println("u1 == u2 with different pointer?", u1 == u2) //false 
  fmt.Println("u1 equals u2 with different pointer?", cmp.Equal(u1, u2)) //true
}

cmp和DeepEqual的区别

性能比较

简单类型的==对比速度最快

复杂类型,自己知道结构之后写的自定义对比速度次之

复杂结构且不确定结构的,使用cmp.Equal()或者reflect.DeepEqual()都可以,就是效率低点

assert.Equal()底层使用的就是reflect.DeepEqual()

总结

对于比较两个struct或者map,slice是否相等,方式很多,效率也有差异。选择合适自己需求的最重要。相对来说,cmp包是要更安全且可操作性更强一点。

到此这篇关于Golang判断struct/slice/map是否相等以及对比的方法总结的文章就介绍到这了,更多相关Golang struct slice map内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:
阅读全文