go函数间通过channel传递数据,核心在于明确谁关闭、谁读取、谁阻塞;错配将导致死锁或panic,且函数参数必须严格匹配channel方向与类型。

Go 函数间通过 channel 传递数据,核心不是“怎么传”,而是“谁关、谁读、谁阻塞”——错配这三点,轻则死锁,重则 panic。
函数参数必须匹配 channel 方向与类型
函数签名里写 chan string 和 (只读)或 <code>chan(只写),行为完全不同:
- 传入
chan string却在函数内只接收?没问题,但调用方可能误往里发数据 - 函数声明接收
,你却传 <code>chan?编译报错:cannot use … as type <li>类型不一致直接拒编译:函数要 <code>chan int,你给chan string——cannot use ch (type chan string) as type chan int
无缓冲 channel 在函数调用中极易卡死
函数里用 make(chan string),又没开 goroutine 配合收发,调用时大概率卡在 ch 或 <code> 上:
- 主流程调用
sendTo(ch, "hello"),而sendTo内部是ch ,但没人接收 → 永久阻塞 - 解决办法不是加 goroutine,而是明确分工:生产函数负责发+关,消费函数用
for range ch;或统一用带缓冲 channel,如make(chan string, 1) - 若函数需“发完就返回”,别用无缓冲,改用
make(chan string, 1)+ 非阻塞发送(select+default)
关闭 channel 必须由唯一生产者完成
多个函数都往同一个 channel 发数据?不能各自关,否则第二个 close(ch) 就 panic:close of closed channel:
- 单生产者场景:发完最后一项后立刻
close(ch),消费者用for s := range ch安全退出 - 多生产者场景:用
sync.WaitGroup计数,等所有 sender 完成再关;或改用context.WithCancel主动通知停止,避免关 channel - 函数内部绝不假设 channel 已关 —— 接收必须用
s, ok := 判断,<code>ok == false才表示真结束
超时和非阻塞必须显式处理,不能依赖 channel 自身
channel 不提供超时能力。函数里写 msg := ,若 sender 崩溃或延迟,调用方就卡住:
- 加
select+time.After:想等最多 500ms,就写case - 非阻塞读取用
select+default,但注意:default 分支会立即执行,不适合“等待数据到达”的语义 - 别在循环里裸写
for { —— 若 channel 永远不关、也没数据,就是无限空转
真正容易被忽略的,是函数边界处的 channel 生命周期管理:传进来的 channel 是谁建的、谁关的、缓冲多少、是否已关 —— 这些信息不会自动随参数传递,必须靠约定或文档明确。没对齐,就只剩 runtime panic 和 debug 到凌晨。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











