概述go 中的空结构体 struct{}{} 的内存大小等于 0,除此之外,还有别的数据类型内存大小也等于 0 吗?
map 实现 setgo 的标准库没有内置的 set 类型,在不引用第三方包的情况下,一般是结合内置的 map 类型实现 set 类型相关功能。
这里假设 set 元素类型为 int, 那么我们就以 int 作为 map 的键类型,以 bool 作为 map 的值类型 (之所以选择 bool 类型,是因为其大小为 1 个字节,相对其他数据类型可以节省内存,当然,也可以使用 byte 类型,其大小同样是 1 个字节)。
package mainimport fmt// set 类型定义type set map[int]bool// 初始化一个新的 setfunc newset() set { return make(set)}// 元素是否存在于与集合中func (s set) contains(ele int) bool { _, ok := s[ele] return ok}// 添加元素到集合func (s set) add(ele int) { s[ele] = true}// 从集合中删除某个元素func (s set) remove(ele int) { delete(s, ele)}func main() { s := newset() fmt.println(s.contains(100)) s.add(100) fmt.println(s.contains(100)) s.remove(100) fmt.println(s.contains(100))}$ go run main.go# 输出如下falsetruefalse上述示例代码通过内置类型 map 实现了 set 类型相关功能,美中不足的一点在于: 每个元素都要浪费一个 bool 类型作为标识占位符, 能否进一步的优化呢 ?当然是可以的,这就是接下来要讲到的 空结构体 了。
空结构体go 中的空结构体 struct{}{} 是 一个底层的内置变量,不占用任何内存 :
package mainimport ( fmt unsafe)func main() { fmt.printf(size = %d\\n, unsafe.sizeof(struct{}{}))}$ go run main.go# 输出如下size = 0结合刚才的例子,可以将 struct{}{} 作为 set 的元素,这样不论 set 有多少个元素,标志位 内存占用始终为 0 。
使用 bool 实现 set测试代码package performanceimport ( testing)// set 类型定义, 使用 bool 类型作为占位符type set map[int]bool// 初始化一个新的 setfunc newset() set { return make(set)}// 元素是否存在于与集合中func (s set) contains(ele int) bool { _, ok := s[ele] return ok}// 添加元素到集合func (s set) add(ele int) { s[ele] = true}// 从集合中删除某个元素func (s set) remove(ele int) { delete(s, ele)}func benchmark_compare(b *testing.b) { s := newset() for i := 0; i < b.n; i++ { s.add(i) } for i := 0; i bool.txt使用空结构体实现 set测试代码package performanceimport ( testing)// set 类型定义, 使用 bool 类型作为占位符type set map[int]struct{}// 初始化一个新的 setfunc newset() set { return make(set)}// 元素是否存在于与集合中func (s set) contains(ele int) bool { _, ok := s[ele] return ok}// 添加元素到集合func (s set) add(ele int) { s[ele] = struct{}{}}// 从集合中删除某个元素func (s set) remove(ele int) { delete(s, ele)}func benchmark_compare(b *testing.b) { s := newset() for i := 0; i < b.n; i++ { s.add(i) } for i := 0; i struct.txt使用 benchstat 比较差异$ benchstat -alpha=100 bool.txt struct.txt# 输出如下name old time/op new time/op delta_compare-8 371ns ± 0% 332ns ± 0% -10.47% (p=1.000 n=1+1)name old alloc/op new alloc/op delta_compare-8 44.0b ± 0% 40.0b ± 0% -9.09% (p=1.000 n=1+1)name old allocs/op new allocs/op delta_compare-8 0.00 0.00 ~ (all equal)从输出的结果中可以看到,相比于使用 bool 作为 set 元素占位符,使用 空结构体 在性能和内存占用方面,都有了小幅度的优化提升 (10% 左右)。因为时间关系,这里的基准测试只运行了 10000000 次, 运行次数越大,优化的效果越明显 。感兴趣的读者可以将 -benchtime 调大后看看优化效果。
小结**go 中的空结构体 **struct{}{} 不占用任何内存,而且有很清晰的语义性质 (作为占位符使用) 。除了刚才示例中实现 set 类型功能外, 还可以使用空结构体作为 通道信号标识、空对象 等,各种使用场景请读者自行探索。
彩蛋除了空结构体 struct{}{} 之外,还有一个鲜为人知的内存大小为 0 的数据类型是: 空数组。但是相对 struct{}{} 丰富的表达性,空数组 使用的场景很少。
package mainimport ( fmt unsafe)func main() { fmt.printf(size = %d\\n, unsafe.sizeof([0]int{}))}$ go run main.go# 输出如下size = 0
LTC3106 简单的宽输入电压降压-升压型转换器
连接器既是“可翻转的”又是可逆的
苹果开发新型激光雷达传感器,或为自动驾驶做铺垫
高速磁悬浮轻量化 需要碳纤维
紫光发超级SIM卡今日上市 128G超大容量存储以及金融级安全能力
Go高性能-两种内存大小为0的数据类型
2020-2023H1锂电池募投资金“流向”
静电在SMT贴片加工生产过程中存在的危害
MCU、NOR Flash涨价并持续供不应求;电机汽车类应用潜力大,头部企业加速布局
平板电脑到底是什么?
广州供电局面向特大城市电网能源互联网项目推出了1+3+3总体架构
丘成桐教授清华大学座谈
三相全桥智能功率模块IPM-CS5755MT(三相无刷直流电机驱动电路5A/500V)
常见的汽车IGBT模块封装类型有哪些?
三菱电机将在2022年6月结束液晶面板生产,退出液晶事业
低压电池供电仍是LED驱动器的主流应用
xG27如何适用于医疗设备和智能家居设备
美方为何打压华为的5G技术
5G、AI、边缘计算、云化释放乘法效应
加法器和乘法器简介及设计