会,而且是运行时 panic。因为 new(chan int) 返回的是 *chan int,其值为 nil 指针,解引用后仍是 nil channel,对其发送、接收或关闭均会触发 panic。

用 new 初始化 chan 会 panic 吗?
会,而且是运行时 panic。因为 new(chan int) 返回的是一个指向 nil channel 的指针,不是可用的 channel 实例。后续任何发送或接收操作(如 ch 或 <code>)都会触发 <code>panic: send on nil channel 或 panic: receive on nil channel。
根本原因:channel 是引用类型,但它的底层结构(如队列、锁、缓冲区等)必须由 make 显式初始化;new 只分配一块全零内存,对 channel 来说就是 nil。
-
new(chan int)→ 得到*chan int,其值为(*chan int)(nil) -
make(chan int)→ 得到可直接使用的chan int,底层已就绪 - 即使解引用
*new(chan int),结果仍是nil,不能绕过这个问题
make(chan T) 的参数怎么选?
channel 的 make 只接受两个参数:make(chan T, buffer),其中 buffer 是缓冲区长度(可选,默认为 0,即无缓冲)。它和 slice 的 cap 不同——这里没有“容量”概念,只有“能暂存多少个值”。
-
make(chan int):创建无缓冲 channel,发送/接收必须配对阻塞 -
make(chan string, 5):创建缓冲为 5 的 channel,最多可缓存 5 个未被接收的值 - 缓冲大小设为 0 和省略第二个参数等价;设为负数会编译报错
- 缓冲区过大可能掩盖同步问题,过小则频繁阻塞,需按实际并发节奏权衡
结构体字段含 chan 时,new 和 make 怎么配合?
new 对结构体只做零值初始化,内部的 chan 字段仍是 nil;必须显式用 make 单独初始化该字段,否则访问会 panic。
例如:
type Worker struct {
jobCh chan int
}
<p>w := new(Worker) // jobCh == nil
w.jobCh </p><p>// 正确做法:
w = &Worker{
jobCh: make(chan int, 10),
}
// 或分步:
w = new(Worker)
w.jobCh = make(chan int, 10)
</p>
- 切记:
new(Worker)不会递归调用make初始化字段 - 如果字段是
chan、map或[]T,它们在new后都是nil,必须单独初始化 - 使用复合字面量(
&Worker{jobCh: make(...)})比new+ 赋值更常见且安全
为什么不能用 new 替代 make 初始化 channel?
因为 channel 不是普通值类型,它的行为依赖运行时维护的内部状态(如 goroutine 队列、互斥锁、缓冲数组等)。new 无法构造这些状态,只返回一个空壳指针。
-
make是编译器特殊处理的内建函数,对chan会触发 runtime.chanmake,完成完整初始化 -
new是通用内存分配器,不感知类型语义,对chan就是分配一个uintptr大小的零值内存 - 即使你用
unsafe强行把new(chan int)转成chan int,依然无法工作——缺少 runtime 注册和初始化逻辑
真正容易被忽略的点:不是“用了 new 就错”,而是“用了 new 还以为能用”。一旦 channel 字段来自 new 或未显式初始化,panic 往往发生在业务逻辑深处,而非声明处。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











