热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

Go快速入门指南类型比较

概述问题:Go中Map的key可以是哪些数据类型呢?我们来看看具体的规则。比较运算符用来比较两个操作数并返回一个bool值,常见的比较运算符:等于!不等于<小于<






概述

问题: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 main
import "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 main
import "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 main
import "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 main
import "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 main
import "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 main
import "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 main
import "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 main
import "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. go.dev/ref/spec#Comparison_operato...

联系我

公众号




go


推荐阅读
  • C# 7.0 新特性:基于Tuple的“多”返回值方法
    本文介绍了C# 7.0中基于Tuple的“多”返回值方法的使用。通过对C# 6.0及更早版本的做法进行回顾,提出了问题:如何使一个方法可返回多个返回值。然后详细介绍了C# 7.0中使用Tuple的写法,并给出了示例代码。最后,总结了该新特性的优点。 ... [详细]
  • 本文介绍了在实现了System.Collections.Generic.IDictionary接口的泛型字典类中如何使用foreach循环来枚举字典中的键值对。同时还讨论了非泛型字典类和泛型字典类在foreach循环中使用的不同类型,以及使用KeyValuePair类型在foreach循环中枚举泛型字典类的优势。阅读本文可以帮助您更好地理解泛型字典类的使用和性能优化。 ... [详细]
  • 本文介绍了Redis的基础数据结构string的应用场景,并以面试的形式进行问答讲解,帮助读者更好地理解和应用Redis。同时,描述了一位面试者的心理状态和面试官的行为。 ... [详细]
  • 本文介绍了如何在给定的有序字符序列中插入新字符,并保持序列的有序性。通过示例代码演示了插入过程,以及插入后的字符序列。 ... [详细]
  • 1,关于死锁的理解死锁,我们可以简单的理解为是两个线程同时使用同一资源,两个线程又得不到相应的资源而造成永无相互等待的情况。 2,模拟死锁背景介绍:我们创建一个朋友 ... [详细]
  • 先看官方文档TheJavaTutorialshavebeenwrittenforJDK8.Examplesandpracticesdescribedinthispagedontta ... [详细]
  • JDK源码学习之HashTable(附带面试题)的学习笔记
    本文介绍了JDK源码学习之HashTable(附带面试题)的学习笔记,包括HashTable的定义、数据类型、与HashMap的关系和区别。文章提供了干货,并附带了其他相关主题的学习笔记。 ... [详细]
  • 本文介绍了一种轻巧方便的工具——集算器,通过使用集算器可以将文本日志变成结构化数据,然后可以使用SQL式查询。集算器利用集算语言的优点,将日志内容结构化为数据表结构,SPL支持直接对结构化的文件进行SQL查询,不再需要安装配置第三方数据库软件。本文还详细介绍了具体的实施过程。 ... [详细]
  • 千万不要错过的后端[纯干货]面试知识点整理 I I
    千万不要错过的后端【纯干货】面试知识点整理IIc++内存管理上次分享整理的面试知识点I,今天我们来继续分享面试知识点整理IIlinuxkernel内核空间、内存管理、进程管理设备、 ... [详细]
  • 本文介绍了使用Java实现大数乘法的分治算法,包括输入数据的处理、普通大数乘法的结果和Karatsuba大数乘法的结果。通过改变long类型可以适应不同范围的大数乘法计算。 ... [详细]
  • LeetCode笔记:剑指Offer 41. 数据流中的中位数(Java、堆、优先队列、知识点)
    本文介绍了LeetCode剑指Offer 41题的解题思路和代码实现,主要涉及了Java中的优先队列和堆排序的知识点。优先队列是Queue接口的实现,可以对其中的元素进行排序,采用小顶堆的方式进行排序。本文还介绍了Java中queue的offer、poll、add、remove、element、peek等方法的区别和用法。 ... [详细]
  • Spring特性实现接口多类的动态调用详解
    本文详细介绍了如何使用Spring特性实现接口多类的动态调用。通过对Spring IoC容器的基础类BeanFactory和ApplicationContext的介绍,以及getBeansOfType方法的应用,解决了在实际工作中遇到的接口及多个实现类的问题。同时,文章还提到了SPI使用的不便之处,并介绍了借助ApplicationContext实现需求的方法。阅读本文,你将了解到Spring特性的实现原理和实际应用方式。 ... [详细]
  • eclipse学习(第三章:ssh中的Hibernate)——11.Hibernate的缓存(2级缓存,get和load)
    本文介绍了eclipse学习中的第三章内容,主要讲解了ssh中的Hibernate的缓存,包括2级缓存和get方法、load方法的区别。文章还涉及了项目实践和相关知识点的讲解。 ... [详细]
  • 本文介绍了使用哈夫曼树实现文件压缩和解压的方法。首先对数据结构课程设计中的代码进行了分析,包括使用时间调用、常量定义和统计文件中各个字符时相关的结构体。然后讨论了哈夫曼树的实现原理和算法。最后介绍了文件压缩和解压的具体步骤,包括字符统计、构建哈夫曼树、生成编码表、编码和解码过程。通过实例演示了文件压缩和解压的效果。本文的内容对于理解哈夫曼树的实现原理和应用具有一定的参考价值。 ... [详细]
  • 本文介绍了Codeforces Round #321 (Div. 2)比赛中的问题Kefa and Dishes,通过状压和spfa算法解决了这个问题。给定一个有向图,求在不超过m步的情况下,能获得的最大权值和。点不能重复走。文章详细介绍了问题的题意、解题思路和代码实现。 ... [详细]
author-avatar
超_级如新公司
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有