Golang里空结构体struct{}的介绍和使用

s t r u c t struct struct G o l a n g Golang Golang里的关键字,用于定义结构类型
比如

type Student struct{
	id int
	name string
}

struct{}是有 0 0 0个元素的结构体.
struct{}{}表示类型struct{}的值为空{}

1.性质

1.1不占用内存

大小为 0 0 0,不需要内存来存储struct{}类型的值。

func Test_Size(t *testing.T) {
	var x int
	var y string
	var z struct{}
	t.Log(unsafe.Sizeof(x), unsafe.Sizeof(y), unsafe.Sizeof(z)) //8 16 0
}

在这里插入图片描述

1.2 地址相同

定义两个struct{}类型的变量,打印并比较其地址,发现是相同的

func Test_Address(t *testing.T) {
	var x struct{}
	var y struct{}
	t.Logf("%p %p %v %v", &x, &y, &x == &y, x == y) // 0x1290460 0x1290460 true true
}

在这里插入图片描述

2.用途

2.1实现set

golang里没有实现set,如果在使用map的时候只关心key,不关心value的话,可以借助struct{}来实现set。比如key为string类型,那么set的实现map[string]struct{}。
因为struct{}不占用空间,所以在查找和判断的过程中速度会快,而且占用的内存也会小
简单实现:

func Test_set(t *testing.T) {
	set := make(map[string]struct{})
	set["a"] = struct{}{}
	if _, ok := set["a"]; ok {
		t.Log("exists") //exists
	}
}

在这里插入图片描述

使用interface{}实现

type Set map[interface{}]struct{}

func (s Set) Add(item interface{}) {
	s[item] = struct{}{}
}

func (s Set) Remove(item interface{}) {
	delete(s, item)
}

func (s Set) Contains(item interface{}) bool {
	_, exists := s[item]
	return exists
}

func Test_any_set(t *testing.T) {
	set := make(Set)

	set.Add("apple")
	set.Add("banana")
	set.Add("orange")

	fmt.Println("Set:", set)

	fmt.Println("Contains apple:", set.Contains("apple"))
	fmt.Println("Contains grape:", set.Contains("grape"))

	set.Remove("banana")

	fmt.Println("Set:", set)
}

在这里插入图片描述
使用泛型实现:

type Set[T comparable] map[T]struct{}

func (s Set[T]) Add(v T) {
	s[v] = struct{}{}
}

func (s Set[T]) Remove(v T) {
	delete(s, v)
}

func (s Set[T]) Contains(v T) bool {
	_, ok := s[v]
	return ok
}

func (s Set[T]) Len() int {
	return len(s)
}

func (s Set[T]) Values() []T {
	values := make([]T, 0, s.Len())
	for v := range s {
		values = append(values, v)
	}
	return values
}

func Test_any_set(t *testing.T) {
	s := Set[string]{}
	s.Add("apple")
	s.Add("banana")
	s.Add("orange")

	fmt.Println("Set:", s.Values())

	fmt.Println("Contains apple:", s.Contains("apple"))
	fmt.Println("Contains grape:", s.Contains("grape"))

	s.Remove("banana")

	fmt.Println("Set:", s.Values())
}

在这里插入图片描述

2.2. 用于无数据的channel

有的时候 c h a n n e l channel channel不需要发送数据,只需要一个触发信号,就可以使用struct{}来减少信号传递过程中的内存开销
a. 等待协程完成
w o r k e r worker worker函数是一个协程,它会模拟一些工作并在完成后发送空结构体值到 d o n e done done通道。
T e s t _ w a i t Test\_wait Test_wait函数中,我们通过从 d o n e done done通道接收空结构体值来等待工作完成。

func worker(done chan struct{}) {
	fmt.Println("Worker: Performing some work...")
	time.Sleep(2 * time.Second)
	fmt.Println("Worker: Work completed!")
	done <- struct{}{} // 发送空结构体值表示工作完成
}
func Test_wait(t *testing.T) {
	done := make(chan struct{})
	go worker(done)
	<-done // 接收空结构体值,等待工作完成
	t.Log("Main: Done!")
}

在这里插入图片描述

b.触发事件
w a i t F o r E v e n t waitForEvent waitForEvent函数会等待接收到空结构体值,表示事件发生。
t r i g g e r E v e n t triggerEvent triggerEvent函数会在一段时间后发送空结构体值到event通道,表示事件发生。
通过使用空结构体值作为通道元素,我们可以简单地实现事件的触发和等待。

func waitForEvent(event chan struct{}) {
	fmt.Println("Waiting for event...")
	<-event // 等待接收到空结构体值,表示事件发生
	fmt.Println("Event received!")
}

func triggerEvent(event chan struct{}) {
	time.Sleep(2 * time.Second)
	fmt.Println("Triggering event...")
	event <- struct{}{} // 发送空结构体值,表示事件发生
}
func Test_event(t *testing.T) {
	event := make(chan struct{})
	go waitForEvent(event)
	go triggerEvent(event)
	time.Sleep(3 * time.Second)
}

在这里插入图片描述

2.3 方法接收器

实现一个接口,只需要实现一些方法,不用声明一些额外的数据,可以用struct{}来实现,也可以换成其他任意的变量,比如 i n t int int b o o l bool bool

type Animal interface {
	Shouting()
}
type Dog struct{}

func (dog *Dog) Shouting() {
	fmt.Println("wang wang wang")
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/294528.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

java中常用的日期API

目录 LocalDateTime类&#xff08;日期时间&#xff09; DateTimeFormater&#xff08;格式化器&#xff09; Period类&#xff08;计算日期间隔&#xff09; Duration类&#xff08;计算时间间隔&#xff09; 本章我要讲的是JDK 8中新增的时间API&#xff0c;因为传统的时间…

【源码预备】Calcite基础知识与概念:关系代数概念、查询优化、sql关键字执行顺序以及calcite基础概念

文章目录 一. 关系代数的基本知识二. 查询优化三. SQL语句的解析顺序1. FROM2. WHERE3. GROUP BY4. HAVING5. SELECT 四. Apache Calcite中的基本概念1. Adapter2. Calcite中的关系表达式2.1. 关系表达式例子2.2. 源码底层结构 3. Calcite的优化规则4. Calcite的Trait--算子物理…

RS485模块常识的解析

1. RS485数据采集模块常识 a) RS485总线基本特性 根据RS485工业总线标准&#xff0c;RS485工业总线为特性阴抗120Ω的半双工通讯总线&#xff0c;其最大负载能力为32个有效负载&#xff08;包括主控设备与被设备&#xff09; b) RS485总线传输距离 当使用0.56mm(24AWG)双绞线作…

rabbitmq延时队列相关配置

确保 RabbitMQ 的延时消息插件已经安装和启用。你可以通过执行以下命令来安装该插件&#xff1a; rabbitmq-plugins enable rabbitmq_delayed_message_exchange 如果提示未安装&#xff0c;以下是安装流程&#xff1a; 查看mq版本&#xff1a; 查看自己使用的 MQ&#xff08;…

Sectigo与Geotrust ov多域名证书的区别

Sectigo和Geotrust都是比较知名的CA认证机构。其中&#xff0c;Sectigo原名Comodo&#xff0c;在2018年整合SSL证书业务&#xff0c;改名为Sectigo&#xff0c;旗下的SSL证书产品根证书也变为Sectigo。Geotrust则是另一个备受信任的数字证书品牌&#xff0c;现在是Digicert旗下…

不会代码(零基础)学语音开发(语音控制舵机)

舵机是一种位置(角度)伺服的驱动器,适用于那些需要角度不断变化并可以保持的控制系统。 舵机,作为模块系列S产品的四大重要组件之一,其在应用中发挥着十分重要的作用。舵机常使用的地方&#xff1a;航模&#xff0c;智能小车&#xff0c;机器人&#xff0c;以及工业领域等等 这…

锐捷 | 策略路由

一、组网要求 1&#xff09;三层交换机的192.168.2.0/24网段访问外网固定走172.16.1.1这条线 2&#xff09;三层交换机的192.168.3.0/24网段访问外网固定走172.16.2.1这条线 二、组网拓扑 三、配置要点 1、根据规划&#xff0c;在设备接口上配置IP地址 2、配置OSPF进程 3、所…

第五周:深度学习知识点回顾

前言&#xff1a; 讲真&#xff0c;复习这块我是比较头大的&#xff0c;之前的线代、高数、概率论、西瓜书、樱花书、NG的系列课程、李宏毅李沐等等等等…那可是花了三年学习佳实践下来的&#xff0c;现在一想脑子里就剩下几个名词就觉得废柴一个了&#xff0c;朋友们有没有同感…

不能错过的AI前沿开源工具!

&#x1f308;&#x1f308;&#x1f308;&#x1f308;&#x1f308;&#x1f308;&#x1f308;&#x1f308; 欢迎关注公众号&#xff08;通过文章导读关注&#xff1a;【11来了】&#xff09;&#xff0c;及时收到 AI 前沿项目工具及新技术 的推送 发送 资料 可领取 深入理…

【软件测试】2024年准备中/高级测试岗技术面试...

目录&#xff1a;导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09; 前言 1、软件测试基础知…

NVM NodeJs版本管理 通关宝典

NVM NodeJs版本管理 通关宝典&#x1f3f9; 文章目录 NVM NodeJs版本管理 通关宝典&#x1f3f9;一、NVM是什么二、开始使用NVM三、NVM 命令速查四、手动安装特定Node版本(Windows)&#x1f644;4.1 NVM for windows 运行机制4.2 手动安装流程 五、切换 NVM 下载镜像源六、常见…

如何实现安卓端与苹果端互通

在移动应用开发中&#xff0c;如何实现安卓端和苹果端的互通是一个重要的问题。二者缺少一个都会有损失&#xff0c;那如何实现安卓端跟苹果端互通&#xff0c;下面简单的介绍几点方法来帮助你再不同的平台上实现数据交互和功能互通。 基于Web技术 使用Web技术是一种常见并且…

ReactNative 常见问题及处理办法(加固混淆)

文章目录 摘要 引言 正文ScrollView内无法滑动RN热更新中的文件引用问题RN中获取高度的技巧RN强制横屏UI适配问题低版本RN&#xff08;0.63以下&#xff09;适配iOS14图片无法显示问题RN清理缓存RN navigation参数取值pod install 或者npm install 443问题处理 打开要处理的…

spark的任务提交方式及流程

本地模式 local 测试用,不多赘述 分布式模式 standalone standalone集群是spark 自带的一个资源调度集群&#xff0c;分为两个角色&#xff0c;master/worker&#xff0c;master负责接收任务请求、资源调度&#xff08;监听端口7077&#xff09;&#xff0c;worker负责运行exec…

汇报学习1

汇报的重点 项目的意义&#xff1a;可复制的经验、未来的领头基层要多具体的案例且真正有意义提拔的人的标准 汇报的维度 多做定期和主动的回报。 适当的工作汇报&#xff0c;也是对对方尊重的体现。&#xff08;每一周或每两三天的回报里&#xff0c;要体现对领导的尊重&#…

【2023年度技术盘点】「年终盘点后端系列」探索服务架构体系的技术风向,构建微服务核心能力(升级版)

探索服务架构体系的技术风向&#xff0c;构建微服务核心能力 文章导航大纲前提背景架构未来的风向云原生化的微服务架构&#xff08;未来软件架构&#xff09;历史历代服务架构路径新时代架构预测服务架构方向—云原生化微服务云原生化微服务提升了哪些方面 云原生化微服务架构…

Vue 之 修饰符汇总

一、简介 在Vue中&#xff0c;修饰符是一种特殊的语法&#xff0c;用于修改指令或事件绑定的行为&#xff0c;它们以点号&#xff08;.&#xff09;的形式添加到指令或事件的后面&#xff0c;并可以改变其默认行为或添加额外的功能&#xff0c;如&#xff1a;禁止事件冒泡、数…

(NeRF学习)NeRF复现 win11

目录 一、获取源码二、环境三、准备数据集1.下载数据集方法一&#xff1a;官方命令方法二&#xff1a;官网下载数据集 2.修改配置 四、开始训练1.更改迭代次数2.开始训练方法一&#xff1a;方法二&#xff1a; 3.使用预训练模型 五、NeRF源码学习 一、获取源码 git clone http…

Vue页面传值:Props属性与$emit事件的应用介绍

一、vue页面传值 在Vue页面中传值有多种方式&#xff0c;简单介绍以下两种 通过props属性传递值&#xff1a;父组件在子组件上定义props属性&#xff0c;子组件通过props接收父组件传递的值。通过$emit触发事件传递值&#xff1a;子组件通过$emit方法触发一个自定义事件&#…