必须用 chan struct{} 而不是 chan bool 或 chan int,因其零内存开销、语义明确(纯信号不传数据)、编译器优化且所有 struct{} 实例可安全比较。

单向 chan 不是语法糖,而是编译期强制的通信契约——用错方向会直接报错,不是运行时 panic。
为什么必须用 chan 和 <code> 而不是靠注释或约定?
很多人在初学时觉得“反正我写函数时只读不写,加个注释说明就行”,但实际协作中,这种信任会迅速崩塌。Go 的单向通道把意图写进类型系统里,让错误在编译阶段暴露。
func process(in :调用方传入任意 <code>chan int或都合法,但函数体内若写 <code>in ,编译失败func feed(out chan:传入 <code>chan string或chan 都行,但函数内无法执行 <code>val :=- 双向通道可隐式转为单向,但单向不能反向转回(类型系统不允许)
make(chan 和 <code>make( 有什么实际用途?
直接用 make 创建单向通道本身意义有限——没人接收的发送通道、没人发送的接收通道,都是死路。但它在接口抽象和测试模拟中很关键。
- 测试时伪造一个只读通道:
mockCh := make(,避免意外写入干扰断言 - 封装 SDK 时返回只读通道:
func Subscribe() ,防止用户误关或写入内部通道 - 注意:
make(chan 创建的通道无法被 <code>close(),因为关闭操作需要双向权限(close只接受chan T)
常见误用:把单向通道当“只读/只写开关”来 runtime 切换
单向性是静态类型属性,不是运行时状态。你不能“先声明为 chan,再某处转成 <code>”。试图绕过类型检查会导致编译失败。
立即学习“go语言免费学习笔记(深入)”;
- 错误写法:
var ch chan → 编译报错:cannot convert <code>chan to <code> - 正确做法:从源头就按角色分配类型,比如生产者函数输出
chan,消费者函数输入 <code>,中间由调用方桥接 - 如果真需要双向能力(如调试注入),应单独暴露一个受控的双向通道,而不是试图“升级”单向类型
容易被忽略的关闭陷阱:谁该关?怎么关?
单向通道本身不决定关闭权,关闭行为仍由原始双向通道持有者控制。但误关会破坏契约。
- 只有创建双向通道的一方能安全调用
close();传递出去的单向引用不能关 - 向已关闭的
chan 发送会 panic:<code>panic: send on closed channel - 从已关闭的
接收会立即返回零值 + <code>ok==false,这是唯一合法的“关闭感知”方式 - 典型错误:在
consumer(in 函数里调用 <code>close(in)→ 编译不过(类型不匹配),但若改成close((chan int)(in))强转,虽能编译,却违反语义且危险
真正难的不是写出单向通道,而是让团队所有人理解:它不是限制“能不能做”,而是明确“该不该做”。一旦类型签名说“只读”,那任何写操作就不再是 bug,而是设计背叛。


















