Go语言select语句case求值规则及c<-x作用疑问
Go select语句发送型case的运行逻辑解析
首先明确核心结论:case c <- x属于发送操作类型的case,它既不是无前提直接发送,也不是匹配「其他协程向c发数据」的条件,它的完整逻辑是:判断当前向通道c发送x的操作是否可以立即执行,若可以则执行发送操作,再运行该case后的代码块。
相关规则说明
Go的select语句执行逻辑是固定的:
- 进入select块时,会先对所有case的操作做可行性检查
- 从所有当前可执行的case中随机选一个执行
- 若所有case都不可执行,且没有default分支,select就会阻塞,直到某个case的操作变为可执行
结合完整代码的运行流程拆解
你给出的完整代码整理后如下:
func fibonacci(c, quit chan int) { x, y := 0, 1 for { select { case c <- x: x, y = y, x+y case <-quit: return } } } func main() { c := make(chan int) quit := make(chan int) // 启动子协程负责接收斐波那契数 go func() { for i := 0; i < 10; i++ { // 这里会从c通道接收数据,没有数据时就会阻塞等待 fmt.Println(<-c) } // 10个数接收完成,往quit通道发信号 quit <- 0 }() fibonacci(c, quit) }
整个程序的运行时序是:
- main协程先初始化两个无缓冲通道
c和quit,启动子协程后调用fibonacci函数 - 子协程第一次循环执行
<-c,因为此时c是空的,子协程阻塞等待接收数据 - fibonacci函数进入select块,检查两个case:
case c <-x:此时c有阻塞的接收方(子协程),发送操作可以执行,于是把x(初始是0)发送到c,然后更新x、y的值,进入下一轮循环
- 子协程收到0后打印,继续下一轮循环,再次执行
<-c阻塞等待 - 重复步骤3-4,直到子协程完成10次接收打印
- 子协程10次接收完成后,往
quit通道发送0 - 此时fibonacci的select块检查到
<-quit可以执行,于是匹配这个case,直接return退出函数,整个循环终止,不会出现无限循环的问题
你误解的核心点
你混淆了发送型case的主体:这个case的操作是fibonacci所在的main协程作为发送方,往c通道发数据,匹配的是「当前发送操作可执行」的条件,不是匹配其他协程往c发数据的条件,不需要其他协程给c发数据。
内容的提问来源于stack exchange,提问作者IcanCode
相关产品推荐
相关产品推荐

