概述
问题:Go 中 Map
的 key
能够是哪些数据类型呢? 咱们来看看具体的规定。
比拟运算符
用来比拟两个操作数并返回一个 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
- https://go.dev/ref/spec#Compa...