当前位置: 首页 > news >正文

十分钟掌握Go语言==运算符与reflect.DeepEqual函数处理interface{}值的比较规则

在 Go 语言中,interface{} 类型是一种特殊的接口类型,它表示任意类型的值。你可以使用 == 运算符来检测任意两个 interface{} 类型值的相等性,比较的规则和一般的接口类型一样,需要满足以下条件:

  • 两个 interface{} 值的动态类型必须相同,也就是说,它们存储的具体类型必须一致。
  • 两个 interface{} 值的动态值必须相等,也就是说,它们存储的具体值必须可以比较的。

根据 Go 语言规范的描述,interface{} 类型的值在内存中是由两个字(word)组成的,一个字存储了动态类型的信息,另一个字存储了动态值的信息。如果动态值的大小超过了一个字,那么这个字就存储了动态值的指针,指向实际的动态值。

Go 编译器是如何判定 interface{} 值是否相等的呢?

使用 == 符号比较两个 interface{} 类型的值时,Go编译器会先比较它们的动态类型,也就是比较它们的第一个字,看是否指向相同的类型信息。如果不相同直接返回 false,如果相同,则继续比较它们的动态值,也就是比较它们的第二个字,看是否相等。如果动态值的大小超过了一个字,那么这个字就是一个指针,需要根据指针找到实际的动态值,并且根据动态类型的规则进行比较。

例如,如果动态类型是数组,那么就需要逐个比较数组的元素,如果动态类型是结构体,那么就需要逐个比较结构体的字段,以此类推。

下面是一个简单的例子,演示了如何使用 == 符号比较两个 interface{} 类型的值:

package mainimport "fmt"func main() {var a, b interface{}// 给 a 赋值为 int64 类型的 1a = int64(1)// 给 b 赋值为 int64 类型的 2b = int64(2)// a和b的动态类型相同, 动态值不同, 输出结果为 falsefmt.Println(a == b) // false// 给 b 赋值为 int64 类型的 1b = int64(1)// a和b的动态类型相同, 动态值也相同, 此时输出结果为truefmt.Println(a == b) // true// 给 b 赋值为 float32 类型的 1b = float32(1)// 此时a和b的动态类型不相同, 就不会进行动态值的处理, 输出结果为falsefmt.Println(a == b) // false// 给 a,b 赋值为 int 类型的数组a = [5]int{1, 2, 3, 4, 5}b = [5]int{1, 2, 3, 4, 5}fmt.Println(a == b) // true// 给 b 赋值为 int 类型的数组b = [5]int{1, 2, 3, 4, 6}fmt.Println(a == b) // false// 给 b 赋值为 int 类型的切片b = []int{1, 2, 3, 4, 5}// 此时a和b的动态类型已然不相同, 就不会进行动态值的处理, 输出结果为falsefmt.Println(a == b) // false// 给 a 赋值为 int 类型的切片a = []int{1, 2, 3, 4, 5}// 此时a和b的动态类型和动态值虽然相同, 但是在Go语言中切片类型的值是不能用 == 符号比较,会引发运行时错误//fmt.Println(a == b) // panic: runtime error: comparing uncomparable type []int
}

== 运算符通常只能用于比较基本类型和支持 == 操作的复合类型,如数组、结构体等,而不能用于比较切片、映射、函数等类型,否则会引发编译错误或运行时错误。

那么问题来了,如果一定要比较两个切片、映射、函数的相等性,该如何操作呢?

reflect.DeepEqual 函数原型:

// 用于判断两个值是否深度一致
// 
// 除了类型相同;在可以时(主要是基本类型)会使用==;但还会比较array、slice的成员,
// map的键值对,结构体字段进行深入比对。map的键值对,对键只使用==,但值会继续往深
// 层比对。DeepEqual函数可以正确处理循环的类型。函数类型只有都会nil时才相等;空切
// 片不等于nil切片;还会考虑array、slice的长度、map键值对数。
func DeepEqual(x, y any) bool

对于 reflect.DeepEqual 而言,它通过牺牲程序的性能来弥补 == 运算符无法处理切片、映射、函数的短板,对于不支持 == 操作的类型,reflect.DeepEqual 函数会有一套自己的比较规则。

你可以把 reflect.DeepEqual 函数理解成是 == 运算符的扩展版!下面是一个简单的例子,演示了如何使用 reflect.DeepEqual 函数:

package mainimport "fmt"func main() {var a, b interface{}// 给 a 赋值为 int64 类型的 1a = int64(1)// 给 b 赋值为 int64 类型的 2b = int64(2)fmt.Println(a == b, reflect.DeepEqual(a, b))b = int64(1)fmt.Println(a == b, reflect.DeepEqual(a, b))b = float32(1)fmt.Println(a == b, reflect.DeepEqual(a, b))// 给 b 赋值为 int 类型的切片a, b = []int{1, 2, 3, 4, 5}, []int{1, 2, 3, 4, 5}fmt.Println(reflect.DeepEqual(a, b)) // trueb = []int{5, 4, 3, 2, 1}fmt.Println(reflect.DeepEqual(a, b)) // false
}

 

相关文章:

十分钟掌握Go语言==运算符与reflect.DeepEqual函数处理interface{}值的比较规则

在 Go 语言中,interface{} 类型是一种特殊的接口类型,它表示任意类型的值。你可以使用 运算符来检测任意两个 interface{} 类型值的相等性,比较的规则和一般的接口类型一样,需要满足以下条件: 两个 interface{} 值的…...

Unity3d Shader篇(一)— 顶点漫反射着色器解析

文章目录 前言一、顶点漫反射着色器是什么?1. 顶点漫反射着色器的工作原理 二、编写顶点漫反射着色器1. 定义属性2. 创建 SubShader3. 编写着色器程序段4. 完成顶点着色器5. 完成片段着色器 三、效果四、总结 前言 在 Unity 中,Shader 可以用来实现各种…...

WordPress主题YIA的文章页评论内容为什么没有显示出来?

有些WordPress站长使用YIA主题后,在YIA主题设置的“基本”中没有开启“一键关闭评论功能”,而且文章也是允许评论的,但是评论框却不显示,最关键的是文章原本就有的评论内容也不显示,这是为什么呢? 根据YIA主…...

选择低代码应该注意什么?如何选择?

我查看了几乎所有的介绍低代码的总结和分析报告,几乎都没有把低代码最底层的产品逻辑说清楚。今天我尝试不用复杂的技术名词,也不用代码,把这个事儿给大家说明白,低代码到底怎么回事儿!(人云亦云那些&#…...

橘子学linux调优之工具包的安装

今天在公司无聊的弄服务器,想着有些常用的工具包安装一下,这里就简单记录一下。 一、sysstat的安装和使用 1、安装 我是通过源码的方式安装的,这样的好处在于可以自由选择你的版本,很直观。 直接去github上找到sysstat的地址&a…...

函数的连续与间断【高数笔记】

【连续】 分类,分几个?每类特点? 连续条件,是同时满足还是只需其一? 【间断】 分类,分几个大类,又分几个小类?每类特点? 间断条件,是同时满足还是只需其一&am…...

游戏如何选择服务器

选择游戏服务器是一个综合性的过程,涉及到的因素包括但不限于游戏类型和规模、硬件配置、网络质量、安全性、服务商的声誉以及地理分布等。以下是一些具体的指导原则: 游戏类型和规模:根据游戏的具体需求来选择合适的服务器。例如&#xff0…...

ubuntu20安装mysql8

1.安装 sudo apt update sudo apt install mysql-server-8.0 -y2.查看运行状态 yantaoubuntu20:~$ sudo systemctl status mysql ● mysql.service - MySQL Community ServerLoaded: loaded (/lib/systemd/system/mysql.service; enabled; vendor preset:>Active: active …...

07 SB3之@HttpExchange(TBD)

HttpExchange是SpringBoot3的新特性. Spring Boot3 提供了新的 HTTP 的访问能力,封装了Http底层细节. 通过接口简化 HTTP远程访问,类似 Feign 功能。 SpringBoot 中定义接口提供 HTTP 服务 --> 框架生成的代理对象实现此接口 --> 框架生成的代理…...

Redis数据淘汰策略

Redis作为一种高性能的键值存储数据库,通常用于缓存和提高数据检索速度。然而,由于内存资源有限,当内存不足以容纳所有数据时,Redis就需要采取一些策略来删除部分数据,以确保新的数据能够被写入。这就引入了数据淘汰策…...

Git的一些基本操作

初始git 我们给出下面的一个场景,在大学里,一些老师在我们做完实验之后喜欢让我们交实验报告,假设我们有一个比较追求完美的老师和一个勤奋的学生,这个学生叫做小帅,那天小帅桑勤奋的完成实验报告,在第二天…...

Spring Boot中异步线程池@Async

很多业务场景需要使用异步去完成,比如:发送短信通知。要完成异步操作一般有两种: 1、消息队列MQ 2、线程池处理。 我们来看看Spring框架中如何去使用线程池来完成异步操作,以及分析背后的原理。 一. Spring异步线程池的接口类 …...

ArcGIS学习(五)坐标系-2

3.不同基准面坐标系之间的转换 在上一关中,我们学习了ArcGIS中的投影(投影栅格)工具,并以"WGS1984地理坐标系与WGS1984的UTM投影坐标系的转换”为例进行讲解。 "WGS1984地理坐标系与WGS1984的UTM投影坐标系的转换”代表的是同一个基准面下的两个坐标的转换。 …...

2024Node.js零基础教程(小白友好型),nodejs新手到高手,(五)NodeJS入门——http模块

044_http模块_创建HTTP服务端 hello,大家好,那这个小节我们来使用 nodejs 创建一个 http 的服务,有了这个 http 服务之后,我们就可以处理浏览器所发送过来的请求,并且还可以给这个浏览器返回响应。 顺便说一下&#x…...

sklearn.preprocessing 标准化、归一化、正则化

文章目录 数据标准化的原因作用归一化最大最小归一化针对规模化有异常的数据标准化线性比例标准化法log函数标准化法正则化Normalization标准化的意义数据标准化的原因 某些算法要求样本具有零均值和单位方差;需要消除样本不同属性具有不同量级时的影响: ① 数量级的差异将导…...

Windows系统编程(一) 文件与目录操作

以下程序需要包含<Windows.h>头文件 创建打开文件 HANDLE hFile CreateFile("D:\\rkvir.ini", GENERIC_READ | GENERIC_WRITE, NULL, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); 此处打开文件&#xff0c;参数依次 已有文件的路径&#xff0c;注意…...

6-2、T型加减速计算简化【51单片机+L298N步进电机系列教程】

↑↑↑点击上方【目录】&#xff0c;查看本系列全部文章 摘要&#xff1a;本节介绍简化T型加减速计算过程&#xff0c;使其适用于单片机数据处理。简化内容包括浮点数转整型数计算、加减速对称处理、预处理计算 一、浮点数转整型数计算 根据上一节内容已知 常用的晶振大小…...

配置Jenkins自动构建打包项目

转载说明&#xff1a;如果您喜欢这篇文章并打算转载它&#xff0c;请私信作者取得授权。感谢您喜爱本文&#xff0c;请文明转载&#xff0c;谢谢。 需求说明 1、给A项目配置jenkins每2小时无条件自动构建一次&#xff0c;无论是否有代码提交。 2、给B项目配置jenkins每15分钟检…...

进阶C语言-通讯录的实现

通讯录 🎈1.设计要求🎈2.程序实现🔭2.1打印菜单及初始化通讯录🔭2.2显示所有联系人🔭2.3查找指定的联系人🔭2.4删除指定的联系人🔭2.5查找指定的联系人🔭2.6修改指定联系人🔭2.7按照年龄排序(以此为例)🎈3.全部源码以及实现🎈1.设计要求 🌞通过前面…...

STM32单片机的基本原理与应用(七)

超声波测距实验 基本原理 超声波测距实验是STM32单片机通过控制HC-SR04超声波模块&#xff0c;使其发送超声波&#xff0c;遇到物体反射回超声波来实现距离测量&#xff0c;其原理就是在发射超声波到接收超声波会有一段时间&#xff0c;而超声波在空气中传播的速度为声速&…...

《用户共鸣指数(E)驱动品牌大模型种草:如何抢占大模型搜索结果情感高地》

在注意力分散、内容高度同质化的时代&#xff0c;情感连接已成为品牌破圈的关键通道。我们在服务大量品牌客户的过程中发现&#xff0c;消费者对内容的“有感”程度&#xff0c;正日益成为影响品牌传播效率与转化率的核心变量。在生成式AI驱动的内容生成与推荐环境中&#xff0…...

渲染学进阶内容——模型

最近在写模组的时候发现渲染器里面离不开模型的定义,在渲染的第二篇文章中简单的讲解了一下关于模型部分的内容,其实不管是方块还是方块实体,都离不开模型的内容 🧱 一、CubeListBuilder 功能解析 CubeListBuilder 是 Minecraft Java 版模型系统的核心构建器,用于动态创…...

[ICLR 2022]How Much Can CLIP Benefit Vision-and-Language Tasks?

论文网址&#xff1a;pdf 英文是纯手打的&#xff01;论文原文的summarizing and paraphrasing。可能会出现难以避免的拼写错误和语法错误&#xff0c;若有发现欢迎评论指正&#xff01;文章偏向于笔记&#xff0c;谨慎食用 目录 1. 心得 2. 论文逐段精读 2.1. Abstract 2…...

【OSG学习笔记】Day 16: 骨骼动画与蒙皮(osgAnimation)

骨骼动画基础 骨骼动画是 3D 计算机图形中常用的技术&#xff0c;它通过以下两个主要组件实现角色动画。 骨骼系统 (Skeleton)&#xff1a;由层级结构的骨头组成&#xff0c;类似于人体骨骼蒙皮 (Mesh Skinning)&#xff1a;将模型网格顶点绑定到骨骼上&#xff0c;使骨骼移动…...

CRMEB 框架中 PHP 上传扩展开发:涵盖本地上传及阿里云 OSS、腾讯云 COS、七牛云

目前已有本地上传、阿里云OSS上传、腾讯云COS上传、七牛云上传扩展 扩展入口文件 文件目录 crmeb\services\upload\Upload.php namespace crmeb\services\upload;use crmeb\basic\BaseManager; use think\facade\Config;/*** Class Upload* package crmeb\services\upload* …...

Unit 1 深度强化学习简介

Deep RL Course ——Unit 1 Introduction 从理论和实践层面深入学习深度强化学习。学会使用知名的深度强化学习库&#xff0c;例如 Stable Baselines3、RL Baselines3 Zoo、Sample Factory 和 CleanRL。在独特的环境中训练智能体&#xff0c;比如 SnowballFight、Huggy the Do…...

vue3+vite项目中使用.env文件环境变量方法

vue3vite项目中使用.env文件环境变量方法 .env文件作用命名规则常用的配置项示例使用方法注意事项在vite.config.js文件中读取环境变量方法 .env文件作用 .env 文件用于定义环境变量&#xff0c;这些变量可以在项目中通过 import.meta.env 进行访问。Vite 会自动加载这些环境变…...

今日学习:Spring线程池|并发修改异常|链路丢失|登录续期|VIP过期策略|数值类缓存

文章目录 优雅版线程池ThreadPoolTaskExecutor和ThreadPoolTaskExecutor的装饰器并发修改异常并发修改异常简介实现机制设计原因及意义 使用线程池造成的链路丢失问题线程池导致的链路丢失问题发生原因 常见解决方法更好的解决方法设计精妙之处 登录续期登录续期常见实现方式特…...

Spring是如何解决Bean的循环依赖:三级缓存机制

1、什么是 Bean 的循环依赖 在 Spring框架中,Bean 的循环依赖是指多个 Bean 之间‌互相持有对方引用‌,形成闭环依赖关系的现象。 多个 Bean 的依赖关系构成环形链路,例如: 双向依赖:Bean A 依赖 Bean B,同时 Bean B 也依赖 Bean A(A↔B)。链条循环: Bean A → Bean…...

SiFli 52把Imagie图片,Font字体资源放在指定位置,编译成指定img.bin和font.bin的问题

分区配置 (ptab.json) img 属性介绍&#xff1a; img 属性指定分区存放的 image 名称&#xff0c;指定的 image 名称必须是当前工程生成的 binary 。 如果 binary 有多个文件&#xff0c;则以 proj_name:binary_name 格式指定文件名&#xff0c; proj_name 为工程 名&…...