概述

问题:Go 中 Mapkey 能够是哪些数据类型呢? 咱们来看看具体的规定。

比拟运算符 用来比拟两个操作数并返回一个 bool 值,常见的比拟运算符:

==    等于!=    不等于<     小于<=    小于等于>     大于>=    大于等于

在任何比拟中,第一个操作数必须能够赋值给第二个操作数的类型,反过来也一样。

不可比拟类型

Go 中有 3 种数据类型不能比拟,别离是 slice, map, func,如果要比拟这 3 种类型,
应用 reflect.DeepEqual 函数。

为什么 slice 不能比拟

(集体猜想,待验证)

  • 切片是援用类型,比拟地址没有意义
  • 多个切片援用同一数组时,批改时会相互影响,无奈保障 key 的一致性
  • 切片除了 len 属性外,还有 cap 属性,比拟的维度没方法准确掂量

基于上述起因,官网没有反对 slice 类型的比拟。

为什么 map 不能比拟

(集体猜想,待验证)

  • map 遍历是随机的,无奈保障 key 的一致性

为什么 func 不能比拟

(集体猜想,待验证)

  • 函数的可变参数机制,无奈保障 key 的一致性
  • 函数参数能够为 slice, map, 这两种类型不可比拟

可比拟类型的具体规定

  • 布尔值 可比拟
  • 整型 可比拟
  • 浮点型 可比拟。如果两个浮点型值一样 (由 IEEE-754 规范定义),则两者相等
  • 复数型 可比拟。如果两个复数型值的 real() 办法 和 imag() 办法都相等,则两者相等
  • 字符串 可比拟
  • 指针 可比拟。如果两个指针指向雷同的 地址 或者两者都为 nil,则两者相等,然而指向不同的零大小变量的指针可能不相等
  • 通道 可比拟。如果两个通道是由同一个 make 创立的 (援用的是同一个 channel 指针),或者两者都为 nil, 则两者相等
  • 接口 可比拟。interface 的外部实现蕴含了 2 个字段,类型 T 和 值 V。 如果两个 接口
    具备雷同的动静类型和动静值,或者两者都为 nil, 则两者相等
  • 构造体 可比拟 (如果两个构造体的所有字段都是可比拟的)。如果两个构造体对应的非空白字段相等,则两者相等
  • 数组 可比拟 (如果两个数组的所有元素都是可比拟的)。如果两个数组的所有对应元素相等,则两者相等

例子

指针的比拟

指向雷同的地址的指针

package mainimport "fmt"func main() {    n := 1024    p := &n    p2 := &n    fmt.Printf("p == p2: %t\n", p == p2)}// $ go run main.go// 输入如下/**  p == p2: true*/

指向 nil 的指针

package mainimport "fmt"func main() {    var p *string    var p2 *string    fmt.Printf("p == p2: %t\n", p == p2)}// $ go run main.go// 输入如下/**  p == p2: true*/

通道的比拟

同一个 make() 创立的通道

package mainimport "fmt"func main() {    ch := make(chan bool)    ch2 := make(chan bool)    p := &ch    p2 := &ch2    fmt.Printf("p == p2: %t\n", p == p2)    p3 := &ch    fmt.Printf("p == p3: %t\n", p == p3)}// $ go run main.go// 输入如下/**  p == p2: false  p == p3: true*/

通道为 nil

package mainimport "fmt"func main() {    var p *chan bool    var p2 *chan bool    fmt.Printf("p == p2: %t\n", p == p2)}// $ go run main.go// 输入如下/**  p == p2: true*/

构造体的比拟

比拟的前提: 两个构造体的所有字段都是可比拟的,相等是指: 字段类型、字段个数、字段程序、字段值完全一致

构造体对应的非空白字段相等

package mainimport "fmt"type person struct {    name string    age  int}func main() {    tom := person{        name: "Tom",        age:  6,    }    jerry := person{        name: "Jerry",        age:  8,    }    fmt.Printf("tom == jerry: %t\n", tom == jerry)    nobody := person{}    nobody2 := person{}    fmt.Printf("nobody == nobody2: %t\n", nobody == nobody2)}// $ go run main.go// 输入如下/**  tom == jerry: false  nobody == nobody2: true*/

构造体为 nil

package mainimport "fmt"type person struct {    name string    age  int}func main() {    var nobody person    var nobody2 person    fmt.Printf("nobody == nobody2: %t\n", nobody == nobody2)}// $ go run main.go// 输入如下/**  nobody == nobody2: true*/

接口的比拟

具备雷同的动静类型和动静值

package mainimport "fmt"type person struct {    name string}func main() {    var tom1, tom2 interface{}    tom1 = &person{"Tom"}    tom2 = &person{"Tom"}    var tom3, tom4 interface{}    tom3 = person{"Tom"}    tom4 = person{"Tom"}    fmt.Printf("tom1 == tom2: %t\n", tom1 == tom2) // false    fmt.Printf("tom3 == tom4: %t\n", tom3 == tom4) // true}// $ go run main.go// 输入如下/**  tom1 == tom2: false  tom3 == tom4: true*/

下面的示例代码中,tom1 和 tom2 对应的类型是 *person,值是 person 构造体的地址,然而两个地址不同,因而两者不相等,
tom3 和 tom4 对应的类型是 person,值是 person 构造体且各字段相等,因而两者相等。

接口为 nil

package mainimport "fmt"func main() {    var tom1, tom2 interface{}    fmt.Printf("tom1 == tom2: %t\n", tom1 == tom2) // true}// $ go run main.go// 输入如下/**  tom1 == tom2: true*/

小结

本大节介绍了 Go 的比拟运算符以及各种数据类型的比拟规定。Go 中大多数数据类型都是能够比拟的,
除了 slice, map, func 这 3 种,对于不能比拟的起因,笔者给出了一些猜想,感兴趣的读者能够自行验证。
限于工夫和篇幅,没有给出所有数据类型的代码示例,读者能够编写代码验证具体的类型比拟规定。

reference

  1. https://go.dev/ref/spec#Compa...

分割我