You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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)
}

整个程序的运行时序是:

  1. main协程先初始化两个无缓冲通道c和quit,启动子协程后调用fibonacci函数
  2. 子协程第一次循环执行<-c,因为此时c是空的,子协程阻塞等待接收数据
  3. fibonacci函数进入select块,检查两个case:
    • case c <-x:此时c有阻塞的接收方(子协程),发送操作可以执行,于是把x(初始是0)发送到c,然后更新x、y的值,进入下一轮循环
  4. 子协程收到0后打印,继续下一轮循环,再次执行<-c阻塞等待
  5. 重复步骤3-4,直到子协程完成10次接收打印
  6. 子协程10次接收完成后,往quit通道发送0
  7. 此时fibonacci的select块检查到<-quit可以执行,于是匹配这个case,直接return退出函数,整个循环终止,不会出现无限循环的问题

你误解的核心点

你混淆了发送型case的主体:这个case的操作是fibonacci所在的main协程作为发送方,往c通道发数据,匹配的是「当前发送操作可执行」的条件,不是匹配其他协程往c发数据的条件,不需要其他协程给c发数据。


内容的提问来源于stack exchange,提问作者IcanCode

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.04 08:09:03