
1. Go通道发送操作的本质:语句而非表达式
在go语言中,通道(channel)是实现goroutine之间通信的关键机制。发送操作c 语句,它执行一个动作(将数据发送到通道),但不产生任何可供评估的值。
尝试将c 编译错误,提示“send statement c
2. select语句与switch语句的区别
理解select语句如何处理通道操作至关重要,它与switch语句的工作原理有本质区别。
- switch语句:switch语句通过评估其case表达式来决定执行哪个分支。它会查找与switch表达式匹配的case值,或者在没有switch表达式时,查找第一个评估为true的case表达式。
- select语句:select语句并非通过评估case表达式的布尔值来工作。相反,它关注的是通道操作(发送或接收)的非阻塞性(readiness)。select会检查所有case中的通道操作,寻找那些当前可以立即执行而不会阻塞的。如果多个case都准备就绪,select会随机选择一个执行。一旦一个case被选中,其内部的通道操作(如c
因此,当select语句中的case c
3. 示例代码解析
以下是一个经典的斐波那契数列生成器,它使用select语句处理通道发送和接收:
立即学习“go语言免费学习笔记(深入)”;
package main
import (
"fmt"
)
// fibonacci 函数通过通道c发送斐波那契数列,并通过quit通道接收退出信号
func fibonacci(c, quit chan int) {
x, y := 1, 1 // 初始化斐波那契数列的起始值
for { // 无限循环
select {
case c <- x: // 尝试将x发送到通道c
// 如果c通道准备好接收,则执行发送操作,并更新x和y的值
x, y = y, x + y
case <-quit: // 尝试从quit通道接收值
// 如果quit通道准备好发送(即有值可接收),则执行接收操作,并打印退出信息然后返回
fmt.Println("quit")
return
}
}
}
func main() {
c := make(chan int) // 创建一个用于传输斐波那契数的通道
quit := make(chan int) // 创建一个用于发送退出信号的通道
// 启动一个goroutine来从c通道接收10个斐波那契数
go func() {
for i := 0; i < 10; i++ {
fmt.Println(<-c) // 从c通道接收并打印斐波那契数
}
quit <- 0 // 接收完10个后,向quit通道发送一个值,通知fibonacci函数退出
}()
fibonacci(c, quit) // 调用fibonacci函数,开始生成数列
}在上述fibonacci函数中:
- case c
- case
4. 接收操作与发送操作的区别
值得注意的是,接收操作与发送操作有所不同。接收操作可以产生一个值(或两个值,包括一个布尔ok指示符)。例如:
- value :=
- value, ok :=
在使用短声明(:=)的接收操作中,声明的变量(如value或ok)的作用域仅限于其所在的case块内部。如果需要在case块外部使用接收到的值,应使用常规赋值语句(例如var value int; case value =
5. 总结与注意事项
- c 尝试将其用作值会导致编译错误。
- select语句基于通道操作的“就绪性”来选择分支,而非评估case表达式的布尔值。
- 当select中的case c
- 接收操作(
深入理解这些基本概念对于编写健壮、高效的Go并发程序至关重要。建议查阅Go语言官方规范中关于select语句的部分,以获取最权威和详细的解释。










