选择go中的语句和所选案例

选择go中的语句和所选案例,go,Go,我有一个代码,试图理解为什么选择第二个案例而不是第一个 以下是一个例子: package main import ( "fmt" "time" "log" ) func foo1() string { log.Println("foo1 evaluated") return "quick thing" } func foo2(c chan string

我有一个代码,试图理解为什么选择第二个案例而不是第一个

以下是一个例子:

package main

import (
    "fmt"
    "time"
    "log"
)

func foo1() string {
    log.Println("foo1 evaluated")
    return "quick thing"
}

func foo2(c chan string) {
    time.Sleep(5 * time.Second)
    c <- "sleepy thing"
}

func main() {
    c1 := make(chan string)
    c2 := make(chan string)
    
    go foo2(c2)

    select {
    case c1 <- foo1():
        fmt.Println("received", <-c1)
    case msg := <-c2:
        fmt.Println("received", msg)
    }
}

我希望第一个案例“更快”,因为我们已经准备好发送到c1,但事实并非如此,第二个案例被选中。您能帮助我理解这个场景吗?

频道
c1
的案例将永远不会被选择,因为没有从
c1
读取的goroutine。仅当通道准备好读/写时,才会选择该通道。在本例中,
c2
已准备好读取,因为有一个goroutine正在等待写入。如果从
c1
创建另一个goroutine读取,则
c1
c2
都将就绪,并将选择其中一个

打印消息
foo1 evaluated
,因为案例会立即进行评估(即调用foo1),但案例会在值发送到通道之前被阻止。

Per(emphasis mine):

“select”语句的执行分为几个步骤:

  • 对于语句中的所有情况,在输入“select”语句时,接收操作的通道操作数以及send语句的通道和右侧表达式将按源代码顺序精确计算一次。结果是一组要从中接收或发送到的通道,以及要发送的相应值无论选择哪个(如果有的话)通信操作继续,该评估中的任何副作用都会发生。带有短变量声明或赋值的RecvStmt左侧的表达式尚未评估
  • 因此,您将看到对
    foo1进行了评估
    ,因为在选择
    案例
    之前会调用
    foo1()
    。这并不意味着选择了第一个案例-事实上,根据输出,选择了第二个案例,否则就不会打印
    收到的sleepy thing


    无法选择第一个案例,因为
    c1
    的发送和接收在同一个goroutine(运行
    select
    的goroutine)中,并且没有缓冲。

    我认为问题更多的是为什么要打印“foo1 evaluated”,这是因为所有案例都会立即进行评估,无论选择哪一个。通道上的发送和接收都是阻塞操作。如果你在一个频道上发送,而没有人接收,程序就会死锁。
    2009/11/10 23:00:00 foo1 evaluated
    received sleepy thing
    
    Program exited.