Golang 之 struct能不能比较

第8期 距离大叔的80期小目标还有72期,今天大叔要跟你们分享的依旧是golang的基础知识点——struct能不能比较,这个基础问题很考验你们基础和细节,也是面试官比较喜欢问的问题,接下来跟你们一块儿来了解一下吧。golang

struct能不能比较? 很显然这句话包含了两种状况:web

  • 同一个struct的两个实例能不能比较?
  • 两个不一样的struct的实例能不能比较?

划重点

在分析上面两个问题前,先跟你们梳理一下golang中,哪些数据类型是可比较的,哪些是不可比较的:面试

  • 可比较:IntegerFloating-pointStringBooleanComplex(复数型)PointerChannelInterfaceArray
  • 不可比较:SliceMapFunction

下面就跟你们分别分析一下上面两种状况吧数组

同一个struct的两个实例能不能比较

首先,咱们构造一个struct结构体来玩玩吧markdown

type S struct {
 Name string  Age int  Address *int }  func main() {  a := S{  Name: "aa",  Age: 1,  Address: new(int),  }  b := S{  Name: "aa",  Age: 1,  Address: new(int),  }   fmt.Println(a == b) } 复制代码

运行上面的代码发现会打印false。既然能正常打印输出,说明是能够个比较的,接下来让咱们来个死亡两问app

什么能够比较?ide

回到上面的划重点部分,在总结中咱们能够知道,golang中 SliceMapFunction 这三种数据类型是不能够直接比较的。咱们再看看S结构体,该结构体并无包含不可比较的成员变量,因此该结构体是能够直接比较的。函数

为何打印输出false?oop

a 和 b 虽然是同一个struct 的两个实例,可是由于其中的指针变量 Address 的值不一样,因此 a != b,若是a b 在初始化时把 Address 去掉(不给 Address 初始化),那么这时 a == b 为true, 由于ptr变量默认值是nil,又或者给 Address 成员变量赋上同一个指针变量的值,也是成立的。ui

若是给结构体S增长一个Slice类型的成员变量后又是什么状况呢?

type S struct {
 Name string  Age int  Address *int  Data []int }  func main() {  a := S{  Name: "aa",  Age: 1,  Address: new(int),  Data: []int{1, 2, 3},  }  b := S{  Name: "aa",  Age: 1,  Address: new(int),  Data: []int{1, 2, 3},  }   fmt.Println(a == b) } 复制代码

这时候会打印输出什么呢?true?false?实际上运行上面的代码会报下面的错误:

# command-line-arguments
./test.go:37:16: invalid operation: a == b (struct containing []int cannot be compared) 复制代码

a, b 虽然是同一个struct两个赋值相同的实例,由于结构体成员变量中带有了不能比较的成员(slice),是不能够直接用 == 比较的,因此只要写 == 就报错

总结

同一个struct的两个实例可比较也不可比较,当结构不包含不可直接比较成员变量时可直接比较,不然不可直接比较


但在平时的实践过程当中,当咱们须要对含有不可直接比较的数据类型的结构体实例进行比较时,是否是就无法比较了呢?事实上并不是如此,golang仍是友好滴,咱们能够借助 reflect.DeepEqual 函数 来对两个变量进行比较。因此上面代码咱们能够这样写:

type S struct {
 Name string  Age int  Address *int  Data []int }  func main() {  a := S{  Name: "aa",  Age: 1,  Address: new(int),  Data: []int{1, 2, 3},  }  b := S{  Name: "aa",  Age: 1,  Address: new(int),  Data: []int{1, 2, 3},  }   fmt.Println(reflect.DeepEqual(a, b)) } 复制代码

打印输出:

true
复制代码

那么 reflect.DeepEqual 是如何对变量进行比较的呢?

reflect.DeepEqual

DeepEqual函数用来判断两个值是否深度一致。具体比较规则以下:

  • 不一样类型的值永远不会深度相等
  • 当两个数组的元素对应深度相等时,两个数组深度相等
  • 当两个相同结构体的全部字段对应深度相等的时候,两个结构体深度相等
  • 当两个函数都为nil时,两个函数深度相等,其余状况不相等(相同函数也不相等)
  • 当两个interface的真实值深度相等时,两个interface深度相等
  • map的比较须要同时知足如下几个
    • 两个map都为nil或者都不为nil,而且长度要相等
    • 相同的map对象或者全部key要对应相同
    • map对应的value也要深度相等
  • 指针,知足如下其一便是深度相等
    • 两个指针知足go的==操做符
    • 两个指针指向的值是深度相等的
  • 切片,须要同时知足如下几点才是深度相等
    • 两个切片都为nil或者都不为nil,而且长度要相等
    • 两个切片底层数据指向的第一个位置要相同或者底层的元素要深度相等
    • 注意:空的切片跟nil切片是不深度相等的
  • 其余类型的值(numbers, bools, strings, channels)若是知足go的==操做符,则是深度相等的。要注意不是全部的值都深度相等于本身,例如函数,以及嵌套包含这些值的结构体,数组等

两个不一样的struct的实例能不能比较

结论:能够比较,也不能够比较

可经过强制转换来比较:

type T2 struct {
 Name string  Age int  Arr [2]bool  ptr *int }  type T3 struct {  Name string  Age int  Arr [2]bool  ptr *int }  func main() {  var ss1 T2  var ss2 T3  // Cannot use 'ss2' (type T3) as type T2 in assignment  //ss1 = ss2 // 不一样结构体之间是不能够赋值的  ss3 := T2(ss2)  fmt.Println(ss3==ss1) // true } 复制代码

若是成员变量中含有不可比较成员变量,即便能够强制转换,也不能够比较

type T2 struct {
 Name string  Age int  Arr [2]bool  ptr *int  map1 map[string]string }  type T3 struct {  Name string  Age int  Arr [2]bool  ptr *int  map1 map[string]string }  func main() {  var ss1 T2  var ss2 T3   ss3 := T2(ss2)  fmt.Println(ss3==ss1) // 含有不可比较成员变量 } 复制代码

编译报错:

# command-line-arguments
./test.go:28:18: invalid operation: ss3 == ss1 (struct containing map[string]string cannot be compared) 复制代码

问:struct能够做为map的key么

struct必须是可比较的,才能做为key,不然编译时报错

type T1 struct {
 Name string  Age int  Arr [2]bool  ptr *int  slice []int  map1 map[string]string }  type T2 struct {  Name string  Age int  Arr [2]bool  ptr *int }  func main() {  // n := make(map[T2]string, 0) // 无报错  // fmt.Print(n) // map[]   m := make(map[T1]string, 0)  fmt.Println(m) // invalid map key type T1 } 复制代码

上面就是今天要跟你们分享的内容,有什么问题欢迎你们在后台给大叔留言,关注大叔说码,咱们下期见~

参考文档:

  1. https://studygolang.com/pkgdoc
  2. https://studygolang.com/articles/12944?fr=sidebar
相关文章
相关标签/搜索