传值即可,但必须按角色选单向类型(chan

Go 函数间用 chan 传数据,核心就一条:**传值即可,但必须按角色选单向类型(chan 或 <code>),否则并发安全和可维护性立刻崩塌。**
函数参数该传 chan int 还是 ?
取决于函数干啥事——不是“能不能”,而是“该不该”有写权限。
- 只消费数据(如日志处理器、校验器):用
。编译器会拦住你往里写,避免意外发送或重复关闭 - 只生产数据(如数据生成器、API轮询器):用
chan。调用方传进来的 channel 必须支持写,且你不能读它 - 既读又写(极少见,比如带反馈的协程控制器):才用
chan int;但多数时候说明设计已偏离 pipeline 思路 -
chan int可隐式转成单向类型,但反过来不行——所以对外暴露接口时,优先声明单向类型
为什么传 *chan int 是错的?
因为 chan 本身是引用语义的值类型,底层是结构体指针。传 *chan 不仅多余,还埋雷:
- 调用方无法感知你是否在函数内执行了
*c = make(chan int)—— 管道被悄悄替换了 - 多个 goroutine 共享一个
*chan指针,可能误关别人还在用的 channel - 关闭逻辑混乱:
close(*c)和close(c)行为一样,但语义完全错位 - Go 官方文档和所有标准库都只传
chan值,没例外
管道在函数链中怎么不卡死?
常见卡死不是因为逻辑错,而是没处理好 channel 生命周期和阻塞边界:
- 无缓冲 channel:发送和接收必须同时就绪,否则永久阻塞。函数链中若某环节没启动 goroutine 接收,上游就卡住
- nil channel:传入
nil的到 <code>for range或select,直接 hang 住——必须在函数入口判空,或用default分支兜底 - 关闭时机错:消费者函数不能关 channel;只有唯一生产者 goroutine 才能关,且必须在所有发送完成后
- 接收端没退出:用
for v := range ch时,如果 sender 忘关 channel,循环永不结束
实际流转示例:producer → transformer → consumer
这不是玩具代码,是真实可复用的数据流骨架:
func producer(out chanfunc transformer(in <p>func consumer(in </p><p>// 启动 ch1 := make(chan int) ch2 := make(chan int) go producer(ch1) go transformer(ch1, ch2) go consumer(ch2) </p>
注意每个环节的 channel 类型标注、close 位置、以及 go 启动——漏掉任何一个,整个链就断在某个环节上。最易忽略的是:**transformer 关闭 out 是安全的,因为它独占写权限;但它绝不能关 in,哪怕 in 是 chan int 类型。**
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











