空结构体struct{}不占内存,但盲目使用反而可能因对齐、逃逸或gc开销变慢;map[string]struct{}赋值必须用struct{}{},不可省略{};chan struct{}发送需字面量,接收可忽略。

空结构体 struct{} 确实不占内存(unsafe.Sizeof(struct{}{}) 恒为 0),但“用它就能省空间”是典型误判起点——它只在特定容器和语义下生效,盲目替换 map[string]bool 或往结构体里塞它,反而可能因对齐、逃逸或 GC 开销变慢。
map[string]struct{} 赋值必须写 struct{}{},不是 {} 或 struct{}
这是新手最常卡住的编译错误点。Go 不允许把类型当值用:
-
m["key"] = struct{}→ 编译报错:cannot use struct{} as value(这是类型,不是值) -
m["key"] = {}→ 语法错误:缺少类型上下文,无法推导 -
m["key"] = struct{}{}→ ✅ 唯一合法写法,{}是复合字面量,表示该类型的零值
别用 var zero struct{} 再赋值,多一次变量声明,无性能收益,还干扰逃逸分析。
chan struct{} 发送必须带字面量,接收可忽略但不能解构
信号通道的核心是“事件发生”,不是传数据:
- 发送只能写
ch ;<code>ch 或 <code>ch 全部编译失败 - 接收可写成
(忽略值)或 <code>_ = (显式丢弃) _, ok := 会编译报错 —— <code>struct{}没字段,无法解构赋值- 缓冲通道
make(chan struct{}, 1)和make(chan struct{}, 1000)底层都不为 value 分配内存,但语义不同:前者允许发完就走,后者能缓存多个信号
嵌入 struct{} 到结构体时,位置决定是否真省空间
它自身 size 是 0,但会影响字段偏移和填充:
- 放在末尾(如
type S struct { x int64; _ struct{} })→ 编译器可能追加填充字节以满足对齐,unsafe.Sizeof(S{})可能从 8 变成 16 - 放在开头或中间(如
type S struct { _ struct{}; x int64 })→ x 起始偏移仍为 0,总大小保持 8,真正零成本 - 用
*struct{}更糟:指针占 8 字节,且进 GC 扫描队列,完全抵消优势
别把它当万能占位符——语义错位比内存多占更危险
struct{} 的价值不在“空”,而在“只关心存在性”:
- 适合场景:
map[string]struct{}做集合、chan struct{}做退出通知、无状态接口实现(如type Logger struct{}) - 不适合场景:需要 JSON 序列化(
json.Marshal(struct{}{})返回null)、反射判断字段(它没字段)、需唯一地址标识(栈上多个struct{}变量地址可能相同) - 最容易被忽略的一点:它的零内存特性**只在按元素分配的容器中起作用**(
map、chan、[]struct{});一旦涉及指针、方法接收器或嵌入,省下的字节常被对齐和 GC 成本吃掉
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











