传值即可,因chan是引用语义的值类型;应按使用选单向类型(chan

Go 函数接收 chan 类型参数时,传指针还是传值?
传值就行,chan 本身就是引用类型,底层是结构体指针。传 *chan 不仅多余,还容易引发混淆和错误。
- Go 的
chan、map、slice、func、interface{}都是“引用语义”的值类型——赋值或传参时复制的是 header(含指针、长度、容量等),不是底层数组或队列本身 - 写成
func work(c *chan int)意味着你打算在函数内重新赋值*c(比如*c = make(chan int)),这极少必要,且调用方几乎无法感知这种“换管道”行为 - 常见误操作:把
chan当成需要取地址才能修改的普通变量,结果多套一层指针,导致代码难读、channel 关闭逻辑错乱
向函数传 chan int 还是 chan / <code>?
按函数实际使用方式选单向 channel 类型,这是 Go 并发安全的关键约束手段,不是可有可无的装饰。
- 只往 channel 发数据?用
chan —— 调用方传入的必须是可发送的 channel,编译器会阻止你在函数里尝试 <code> - 只从 channel 收数据?用
—— 调用方不能往这个 channel 写,避免竞态和意外关闭 - 双向操作?才用
chan int;但多数场景下,生产者/消费者角色分明,强行用双向反而削弱类型安全 - 注意:
chan int可以隐式转为chan 或 <code>,但反过来不行
函数里关闭传入的 chan 是否安全?
不安全,除非你 100% 确认该 channel 仅由当前 goroutine 独占写入,且调用方明确约定由你负责关闭。
- 多个 goroutine 往同一个
chan发送?谁关谁错——close()多次 panic:panic: close of closed channel - 调用方可能还在往 channel 写数据,你一关,对方
send直接 panic - 正确做法:让 sender(通常是启动 goroutine 的那一方)负责关闭;函数只消费,不关;或用
context.Context+donechannel 协作退出 - 例外:函数内部
make(chan int)自己创建的 channel,生命周期可控,可以关
传 chan 参数时,nil channel 导致阻塞怎么办?
nil channel 在 select 中永远不可读/不可写,如果函数没做防御,就会卡死——这是最隐蔽的并发 hang 之一。
立即学习“go语言免费学习笔记(深入)”;
- 现象:
select { case v := 中若 <code>c == nil,该 case 永远不会触发,整个 select 阻塞 - 解决方法:接收前判空,或用
default分支兜底(适合非关键路径) - 更健壮的做法:在函数签名中明确要求非 nil,文档写清,或用 struct 封装 channel + 状态字段(如
type Reader struct { ch ) - 调试技巧:加日志或用
runtime.Stack()快速定位哪个 select 卡住了
channel 传参看着简单,但类型方向、关闭责任、nil 处理这三点,任何一个没对齐,就可能在高并发下突然崩掉,而且问题难以复现。别依赖“好像能跑”,得看清楚谁创建、谁写、谁读、谁关。










