揭秘 Go 语言中空结构体的强大用法

简介: Go 语言中的空结构体 `struct{}` 不包含任何字段,不占用内存空间。它在实际编程中有多种典型用法:1) 结合 map 实现集合(set)类型;2) 与 channel 搭配用于信号通知;3) 申请超大容量的 Slice 和 Array 以节省内存;4) 作为接口实现时明确表示不关注值。此外,需要注意的是,空结构体作为字段时可能会因内存对齐原因占用额外空间。建议将空结构体放在外层结构体的第一个字段以优化内存使用。

0.前言

在 Go 语言中,空结构体 struct{} 是一个非常特殊的类型。它不包含任何字段,并且不占用任何内存空间。虽然乍一看似乎没什么用,但实际上,空结构体在 Go 编程中有着广泛的应用。本文将结合工作实例详细探讨空结构体的几种典型用法,并解释为什么它们在特定场景下非常有用。


1.特性

1.1 不占用内存空间

接下来我们来验证空结构体是否占用内存空间,并查找不同空结构体的内存地址是否一致。

代码:

QQ_1740625909307.png

输出:

QQ_1740625987970.png

由以上结果可知:

  1. 多个空结构体内存地址相同。
  2. 空结构体占用字节数为 0,即不占用内存空间。
  3. 多个空结构体值相等。

注意:多个空结构体内存地址 可能 相同,具体与 Go 编译器实现有关。

1.2 内存地址可能相同

1.1中我们验证空结构体的内存大小时,也验证了他们的内存地址,发现它们的内存地址一致,那么是不是巧合呢?


代码:

image.png

输出:

QQ_1740626453577.png

查阅相关文章和部分源码后,原因可能如下:

Go 语言的运行时环境中有一个名为 zerobase 的全局变量,它是一个 uintptr 类型,占用 8 个字节。每当分配的内存大小为 0 时,Go 语言会返回这个 zerobase 的地址,而不是分配新的内存空间1。因此,当你创建多个空结构体时,它们可能会返回相同的 zerobase 地址。

1.3 空结构体占用内存空间不为空的特例

空结构体也并不是什么时候都不会占用内存空间,比如空结构体作为另一个结构体字段时,根据位置不同,可能因内存对齐原因,导致外层结构体大小不一。

代码:

image.png

输出:


image.png


可以发现,当空结构体放在另一个结构体最后一个字段时,会触发内存对齐。如果你的程序对内存要求比较严格,则在使用空结构体作为字段时需要考虑这一点。


2. 用法

2.1 实现Go中的set类型:map+struct

空结构体最常用的地方,就是用来实现 set(集合) 类型了。Go 语言在语法层面没有提供 set 类型,但我们可以很方便地使用 map + struct{} 来实现 set 类型,

代码:

image.png

输出:

true

false

false

2.2 信号通知

空结构体另一个经常使用的方法是与 channel 结合当作信号来使用,示例如下:


image.png

输出:

waiting...

goroutine done

main exit

由于 struct{} 并不占用内存,所以实际上 channel 内部只需要将计数器加一即可,不涉及数据传输,故没有额外内存开销。

2.3 申请超大容量Slice

代码:

QQ_1740627891957.png

输出:

slice a size: 24

slice b size: 24


2.4 申请超大容量Array

基于空结构体不占用内存空间的特性,试创建个容量为 100万 的array。

代码:

QQ_1740627714232.png

输出:

array a size: 16000000

array b size: 0

输出可能会因系统架构和 Go 版本而异。

2.5 作为接口实现

代码:

image.png

输出:

写入数据前:Hello, World

!写入了 13 个字节

数据已被丢弃。

3 总结

空结构体 struct{} 在 Go 中虽小却有着巧妙的用途。从节省内存的角度看,它是表示空概念的理想选择。从语义上考虑,使用 struct{} 语义更明确,就是不关注值。由于内存对齐的影响,空结构体字段顺序可能影响外层结构体的大小,建议将空结构体放在外层结构体的第一个字段。无论是使用空结构体实现集合、信号通知和接口等,struct{} 都显示了其独特的价值。











引用:重新认识Golang中的空结构体


相关文章
|
29天前
|
存储 安全 Java
【Golang】(4)Go里面的指针如何?函数与方法怎么不一样?带你了解Go不同于其他高级语言的语法
结构体可以存储一组不同类型的数据,是一种符合类型。Go抛弃了类与继承,同时也抛弃了构造方法,刻意弱化了面向对象的功能,Go并非是一个传统OOP的语言,但是Go依旧有着OOP的影子,通过结构体和方法也可以模拟出一个类。
85 1
|
3月前
|
Cloud Native 安全 Java
Go:为云原生而生的高效语言
Go:为云原生而生的高效语言
269 1
|
3月前
|
Cloud Native Go API
Go:为云原生而生的高效语言
Go:为云原生而生的高效语言
322 0
|
3月前
|
Cloud Native Java Go
Go:为云原生而生的高效语言
Go:为云原生而生的高效语言
212 0
|
3月前
|
Cloud Native Java 中间件
Go:为云原生而生的高效语言
Go:为云原生而生的高效语言
180 0
|
3月前
|
Cloud Native Java Go
Go:为云原生而生的高效语言
Go:为云原生而生的高效语言
275 0
|
3月前
|
数据采集 Go API
Go语言实战案例:多协程并发下载网页内容
本文是《Go语言100个实战案例 · 网络与并发篇》第6篇,讲解如何使用 Goroutine 和 Channel 实现多协程并发抓取网页内容,提升网络请求效率。通过实战掌握高并发编程技巧,构建爬虫、内容聚合器等工具,涵盖 WaitGroup、超时控制、错误处理等核心知识点。
Go: struct 结构体类型和指针【学习笔记记录】
本文是Go语言中struct结构体类型和指针的学习笔记,包括结构体的定义、成员访问、使用匿名字段,以及指针变量的声明使用、指针数组定义使用和函数传参修改值的方法。
|
JSON 编译器 Go
Go-结构体类型详解(声明、初始化、结构体指针、方法、序列化等)
Go-结构体类型详解(声明、初始化、结构体指针、方法、序列化等)
283 0
Go-结构体类型详解(声明、初始化、结构体指针、方法、序列化等)
|
Go C语言
Golang结构体和指针
Golang是一门很特殊的语言,虽然它出生比较晚,但是在很多地方却和现在的编程语言有所不同。现在的编程语言要么是函数式的、要么是面向对象的,而Go语言却有指针、结构体这些概念,并解决了C语言的一些坑。
1568 0

热门文章

最新文章