只有双向通道或只写通道能被close,且必须非nil、未关闭;重复关闭或对nil通道调用close会panic,接收方禁止关闭。

不能对已关闭的通道再次调用 close,否则会 panic;也不能对 nil 通道调用 close —— 这两点是绝大多数运行时崩溃的根源。
哪些通道能被 close?
只有由 make(chan T) 创建的、非 nil 的**双向通道(或只写通道)**才能被 close。接收方不能主动关闭通道,只写通道(chan)本身就不支持接收操作,但可以被发送方关闭。
-
close只能由**发送端**调用,这是语言强制约束 - 从类型系统看:
chan T和chan 都允许 <code>close;但(只读通道)传入后无法调用 <code>close,编译直接报错 - nil 通道调用
close会立即 panic:panic: close of nil channel
close 后还能往通道发数据吗?
不能。一旦调用 close,再向该通道发送数据就会触发 panic:panic: send on closed channel。这个检查在运行时发生,编译器不拦截。
- 常见错误:多个 goroutine 并发发送,没加锁或没协调关闭时机,一个 goroutine 关闭后,另一个仍在
ch - 安全做法:用
sync.Once或原子标志位确保close最多执行一次 - 注意:
close不影响已排队未读取的数据,接收仍可继续直到空
关闭后接收行为怎么判断是否结束?
接收操作本身不会 panic,但需靠「多值接收」语法判断通道是否已关闭:
val, ok := <p><code>ok</code> 为 <code>false</code> 表示通道已关闭且无剩余数据。仅用 <code>val := 会永远阻塞(如果通道为空且未关闭)或读到零值(如果已关闭但缓冲区有数据)。</code></p>
- 循环接收推荐写法:
for val := range ch—— 它隐式检查ok,通道关闭后自动退出 - 但注意:
range对已关闭且含缓冲数据的通道,会逐个读完再退出,不是“立刻停止” - 若通道可能被反复关闭(比如误用),
range会在第一次关闭后退出,后续关闭无效
为什么有时 close 看似没用?
最常被忽略的是:**关闭通道 ≠ 停止 goroutine**。goroutine 若在 select 中等待多个通道,或在循环中未检查 ok,它可能根本不知道通道已关。
- 典型陷阱:生产者关闭通道,消费者还在
for { 死等,因为没用 <code>range或没判ok - 更隐蔽的问题:关闭发生在所有发送完成前,比如用
sync.WaitGroup计数错误,导致提前关闭 - 别依赖
close作同步信号 —— 它只是数据流终点标记,不是 goroutine 协调原语
真正难的不是记住 close 的语法,而是设计好谁关、何时关、关了之后对方怎么感知——这三件事串在一起,漏掉任意一环都容易卡死或 panic。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











