单向 channel 是编译期强制约束,写错方向直接报错,不运行就拦截 bug。

单向 channel 不是语法糖,也不是为了“看起来更规范”,而是编译期强制约束——写错方向直接报错,不运行就拦住 bug。
chan
看 符号在 <code>chan 的哪一侧:它像箭头,指向数据流动终点。
chan:箭头在右 → 数据只能“流出”函数(只能 send):箭头在左 ← 数据只能“流入”函数(只能 recv)
别靠死记,写个测试就行:ch := make(chan int) 赋值给 var sendOnly chan,再试 <code>,编译器立刻报 <code>invalid operation: 。
函数参数用单向 channel 的真实好处
不是“多此一举”,而是防止调用方误操作。比如一个日志推送函数,本意只该发日志,但若参数是 chan int,别人可能顺手加个 去读取,结果阻塞或逻辑错乱。
- 发送专用函数签名必须是
func logTo(ch chan,调用时传双向 <code>ch会被自动转为单向,安全无感 - 接收专用函数如
func consume(ch ,里面连 <code>ch 都编译不过 - 接口定义中用单向 channel(如
type Producer interface { Produce(ch chan),所有实现都受同一约束
make 创建单向 channel 的坑
能写 make(chan 或 <code>make(,但几乎没用——因为没人能往里塞数据,也没人能从空通道读出东西。
ch := make( 合法,但 <code> 永远阻塞(除非有外部 goroutine 往对应双向通道写)ch := make(chan 合法,但你无法在当前作用域接收它,也无法关闭(<code>close()只接受双向或发送型通道)- 真正该用
make创建的,永远是双向通道;单向类型只用于变量声明、函数参数、返回值等“使用上下文”
time.Timer.C 是
因为它是只读单向通道,而 close() 要求通道可写(至少得是 chan 或双向)。强行 close 会编译失败:<code>cannot close receive-only channel。
- 这是设计保护:计时器内部控制发送,外部只应消费,禁止干扰其生命周期
- 类似地,
context.WithCancel返回的Done()方法也返回,目的相同 - 如果你需要“可关闭的只读视图”,得自己封装——用双向通道 + 单向参数暴露,关闭逻辑留在创建方
单向 channel 的价值不在“能做什么”,而在“阻止你做什么”。它不增加功能,但删掉了错误路径——而那些路径,往往要到线上压测才暴露。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











