在Go中,struct{}类型表示一个没有字段的结构体,占用0字节的内存。这是一个有价值的特性,用于在需要确认某个东西存在但不需要数据的情况下,最小化资源消耗——例如,在实现集合、信号结构或事件通道时。
用于集合作为示例:
mySet := make(map[string]struct{}) mySet["foo"] = struct{}{} if _, ok := mySet["foo"]; ok { fmt.Println("foo在mySet中存在") }
struct{}用作值,以表示键的存在。map[string]bool相比,struct{}的方案在内存上更经济。信号通道:
done := make(chan struct{}) // 协程等待完成信号 <-done
在实现集合时,map[string]struct{}与map[string]bool有什么不同?为什么map[string]struct{}更受欢迎,它是否有缺点?
回答:
map[string]struct{}在值上使用0字节,最紧凑的选项——在数据量较大时节省内存。map[string]bool需要1字节的值(内部由于对齐可能占用更多内存)。map[string]struct{}的缺点:无法快速获取所有标记为true的值的列表,如果需要布尔值,仍需遍历键。示例:
set := make(map[string]struct{}) set["Alice"] = struct{}{} _, exists := set["Alice"] // true flags := make(map[string]bool) flags["Alice"] = true _, exists := flags["Alice"] // true
故事
在一个用于存储唯一标识符的项目中,使用了map[string]bool,随着数据的增加,导致内存消耗显著增长——与使用map[string]struct{}的版本相比,增长了数百兆字节。转换为struct{}使内存消耗减半。
故事
新手通过
chan bool信号结束协程。由于协程数量众多,传递值变得多余:没有任何地方分析是true还是false。改为chan struct{}显示了架构不准确并简化了代码。
故事
在库中通过map实现集合,值使用了string。这占用了过多的内存。在代码审核后转换为map[类型]struct{}。错误在负载测试时内存分析后被发现,当应用由于OOM而崩溃时。