Golang数据类型比较详解
作者:xidianhuihui 发布时间:2023-07-17 10:11:21
直接使用==比较的情况
分类 | 说明 | 是否能比较 | 说明 |
---|---|---|---|
基本类型 | 整型( int/uint/int8/uint8/int16/uint16/int32/uint32/int64/uint64/byte/rune等)浮点数( float32/float64)复数类型( complex64/complex128)字符串( string) | 是 | |
引用类型 | 切片(slice)、map | 否 | |
聚合类型(复合类型) | 数组 | 是 | 相同长度的数组可以比较,不同长度的数组不能进行比较 |
结构体 | 是 | 只包含可比较的类型情况下可比较 | |
接口类型 | 如error | 是 |
基本数据类
类型一致且是基本类型,值相等的时候,才能==
非基本类型会panic panic: runtime error: comparing uncomparable type []int
浮点比较
不过基本类型中也要注意浮点型的比较就不像我们现实中的一样,比如0.1+0.2在计算中运行结果就不是0.3了,而是0.30000000000000004了
package main import "fmt" func main() {
var a float64=0.1
var b float64=0.2
// 0.30000000000000004
fmt.Println(a+b)
}
字符串比较
一般的比较运算符(==、!=、<、<=、>=、>)是通过在内存中按字节比较来实现字符串比较的,因此比较的结果是字符串自然编码的顺序。字符串所占的字节长度可以通过函数 len() 来获取,例如 len(str)
比较两个字符是否相等
package golangbase
import (
"fmt"
"testing"
)
func TestString(t *testing.T) {
str1 := "哈哈"
str2 := "哈哈"
fmt.Println(str1 == str2)
}
输出结果为true
引用类型
slice、map
切片之间不允许比较。切片只能与nil值比较
map之间不允许比较。map只能与nil值比较
两个nil也不能比较,会panic
slice、map比较
使用reflect.DeepEqual()
对比规则
相同类型的值是深度相等的,不同类型的值永远不会深度相等。
当数组值(array)的对应元素深度相等时,数组值是深度相等的。
当结构体(struct)值如果其对应的字段(包括导出和未导出的字段)都是深度相等的,则该值是深度相等的。
当函数(func)值如果都是零,则是深度相等;否则就不是深度相等。
当接口(interface)值如果持有深度相等的具体值,则深度相等。
当切片(slice)序号相同,如果值,指针都相等,那么就是深度相等的
当哈希表(map)相同的key,如果值,指针都相等,那么就是深度相等的。
使用示例
package golangbase
import (
"reflect"
"testing"
)
type StructA struct {
Name string
Hobby []string
}
type StructB struct {
Name string
}
func TestDeepEqual(t *testing.T) {
s1 := StructA{Name: "test", Hobby: []string{"唱", "跳"}}
s2 := StructA{Name: "test", Hobby: []string{"唱", "跳"}}
println(reflect.DeepEqual(s1, s2))// true
mp1 := map[int]int{1: 10, 2: 20}
mp2 := map[int]int{1: 10, 2: 20}
println(reflect.DeepEqual(mp1, mp2))// true
}
channel、指针
指针可比较,只要指针指向的地址一样,则相等
由于通过make创建channel后,返回的是一个指针,所以可以比较
c1 := make(chan int, 2)
c2 := make(chan int, 2)
c3 := c1
fmt.Println(c3 == c1) // true
fmt.Println(c2 == c1) // false
聚合类型
数组
数组在go中是必须先确定长度的,也就是长度不能再去扩容。并且它是个值拷贝,做参数传到一个函数中被修改,那么外部的值还是一样的不变的。Slice则相反。那么数组是否可以比较呢,看下面的例子:
package main
import "fmt"
func main() {
a := [2]int{1, 2}
b := [2]int{1, 2}
c := [2]int{1, 3}
d := [3]int{1, 2, 4}
fmt.Println(a == b) // true
fmt.Println(a == c) // false
fmt.Println(a == d) // invalid operation: a == d (mismatched types [2]int and [3]int)
}
可以看出,相同长度的数组是可以比较的,而不同长度的数组是不能进行比较的。原因是什么呢?这是因为数组类型中,数组的长度也是类型的一部分,不同长度的数组那么他们的类型也就被认为不同的,所以无法比较
结构体
只包含可比较的类型情况下可比较
package main
import "fmt"
type A struct {
id int
name string
}
func main() {
a := A{id:5,name:"123"}
b := A{id:5,name:"123"}
c := A{id:5,name:"1234"}
fmt.Println(a == b) // true
fmt.Println(a == c) // false
}
反例,因为slice不可比较,如果结构体包含了slice,则不可比较
package main
import "fmt"
type A struct {
id int
name string
son []int
}
func main() {
a := A{id:5,name:"123",son:[]int{1,2,3}}
b := A{id:5,name:"123",son:[]int{1,2,3}}
fmt.Println(a == b) // invalid operation: a == b (struct containing []int cannot be compared)
}
接口
Go 语言根据接口类型是否包含一组方法将接口类型分成了两类:
使用 runtime.iface结构体表示包含方法的接口
使用 runtime.eface结构体表示不包含任何方法的 interface{} 类型
type eface struct { // 16 字节
_type *_type
data unsafe.Pointer
}
type iface struct { // 16 字节
tab *itab
data unsafe.Pointer
}
一个接口值是由两个部分组成的,即该接口对应的类型和接口对应具体的值
接口值的比较涉及这两部分的比较,只有当类型和值都相等(动态值使用==比较),两个接口值才是相等的。看个例子:
var a interface{} = 0
var b interface{} = 2
var c interface{} = 0
var d interface{} = 0.0
fmt.Println(a == b) // false
fmt.Println(a == c) // true
fmt.Println(a == d) // false
a和c类型相同(都是int),值也相同(都是0,基本类型比较),故两者相等。 a和b类型相同,值不等,故两者不等。 a和d类型不同,a为int,d为float64,故两者不等
最后做个练习
func TestJson(t *testing.T) {
var x, y Data
x = Data{
UUID: "856f5555806443e98b7ed04c5a9d6a9a",
Content: 1,
}
bytes, _ := json.Marshal(x)
_ = json.Unmarshal(bytes, &y)
println(x)
println(y)
println(reflect.DeepEqual(x, y))
}
为什么结果为false?
debug看一下
原因是json.Unmarshal默认会将所有的数字类型转为float64
针对这种情况,可以封装一个DeepEqual方法
func DeepEqual(v1, v2 interface{}) bool {
if reflect.DeepEqual(v1, v2) {
return true
}
bytesA, _ := json.Marshal(v1)
bytesB, _ := json.Marshal(v2)
return bytes.Equal(bytesA, bytesB)
}

来源:https://blog.csdn.net/xidianhuihui/article/details/130115443


猜你喜欢
- 关于“登录”和“注册”的问题已经被很多设计师和交互设计上写过无数遍了,今天我在登录纳米盘网站时受到打击了所以写下此文。事情是这样的:当初租用
- 本游戏程序实现的功能为本地二人对弈中国象棋,实现语言为javascript+VML,在windows 2000 pro+IE 6sp1的环境
- 1 前言很多程序都要求用户输入某种信息,程序一般将信息存储在列表和字典等数据结构中。用户关闭程序时,就需要将信息进行保存,一种简单的方式是使
- 使用本文提供的JavaScript脚本,配合Dreamweaver的层和行为的运用,可以在页面中显示可拖动的精美月历。具体制作步骤如下:1、
- 什么是接口接口是一种定义规范,规定了对象应该具有哪些方法,但并不指定这些方法的具体实现。在 Go 语言中,接口是由一组方法签名(方法名、参数
- 前言综合前述的类、函数、matplotlib等,完成一个随机移动的过程(注意要确定移动的次数,比如10万次),每次行走都完全是随机的,没有明
- WITH ROLLUP 在生成包含小计和合计的报表时,ROLLUP 运算符很有用。ROLLUP 运算符生成的结果集类似于 CUBE 运算符所
- 在我们开始之前,一定要注意这篇文章只针对Windows用户!对于那些使用Windows的人来说,这是一个有趣的想法。如果您想使用python
- 前言matplotlib实际上是一套面向对象的绘图库,它所绘制的图表中的每个绘图元素,例如线条Line2D、文字Text、刻度等在内存中都有
- ini文件即Initialization File初始化文件,在应用程序及框架中常作为配置文件使用,是一种静态纯文本文件,使用记事本即可编辑
- Microsoft SQL Server 7.0安全问题Microsoft Corporation【「Microsoft SQL Serve
- 在标准的dgango项目中,自动生成的目录结构会包括models.py和views.py两个文件,分别在里面写model的代码和contro
- 几乎所有的Python 2程序都需要一些修改才能正常地运行在Python 3的环境下。为了简化这个转换过程,Python 3自带了一个叫做2
- 最近在着手支付宝个人版改版的项目,正好在一些国内知名的SNS网站上分别注册了帐户进行体验。显然一点,国内的SNS都带有Facebook的影子
- MySQL是一个非常流行的小型关系型数据库管理系统,2008年1月16号被Sun公司收购。目前MySQL被广泛地应用在Internet上的中
- pymsqlpymsql是Python中操作MySQL的模块,其使用方法和MySQLdb几乎相同。下载安装pip3 install pymy
- join 方法用于连接字符串数组 s = ['a', 'b', 'c', 'd
- 一、问题代码如下,发现标题的中文显示的是方块import matplotlibimport matplotlib.pyplot as plt
- plt.subplot()plt.subplot(nrows, ncols, index, **kwargs)第一个参数:*args (官网
- 一、说明1. python标准库ssl可实现加密通信2. ssl库底层使用openssl,做了面向对像化改造和简化,但还是可以明显看出ope