
本文详解 go 语言中“通道的通道”及“通道指针的通道”的类型定义、函数签名写法,并强调通道本身即为引用类型,通常无需额外取址,避免常见误用。
在 Go 中,通道(chan)是引用类型,其底层由运行时管理,变量本身存储的是指向内部结构的指针。因此,直接传递 chan T 已能实现共享与通信,*绝大多数场景下无需使用 `chan T`(指向通道的指针)**。但理解其类型语法对深入掌握 Go 类型系统仍具价值。
✅ 正确的类型定义方式
假设元素类型为 int,则:
- 普通通道:chan int
- 通道的指针:*chan int(注意 * 修饰的是整个 chan int)
- 通道中传输该指针:chan *chan int
- 若函数接收此类通道,签名应为:
func handleChanPtr(c chan *chan int) { ptr := <-c // 接收 *chan int ch := *ptr // 解引用,得到 chan int ch <- 42 // 向原始通道发送数据 }
⚠️ 更推荐的方式:直接使用 chan chan T
由于通道天然可共享,更简洁、安全且符合 Go 惯例的做法是:
func handleNestedChan(c chan chan int) {
ch := <-c // 直接接收 chan int
ch <- 100
}
// 使用示例:
func main() {
outer := make(chan chan int, 1)
inner := make(chan int, 1)
go handleNestedChan(outer)
outer <- inner // 发送通道本身(非指针)
fmt.Println(<-inner) // 输出: 100
}❌ 常见错误与注意事项
- chan chan int ✅ 合法,表示“装有 chan int 的通道”;
- chan *chan int ✅ 语法合法,但语义复杂,易引发空指针或竞态;
- chan chan ❌ 错误:chan 是不完整类型,必须指定元素类型(如 chan int);
- *chan int ❌ 不应作为函数参数直接传递通道指针——这违背 Go 通道设计哲学,且增加内存管理负担。
? 总结
- Go 允许嵌套通道类型,语法清晰:chan *chan T 和 chan chan T 均有效;
- 但因通道已是引用类型,优先选择 chan chan T,它更直观、安全、高效;
- 仅在极特殊场景(如需动态重绑定通道变量地址)才考虑 *chan T,日常开发中应避免;
- 所有通道类型必须明确元素类型,不可省略(如 chan 单独出现是语法错误)。
? 提示:可通过 Go Playground 示例 验证上述代码行为。










