为什么当第一个案例实际执行时,这个选择总是运行默认案例?

m90*_*m90 7 select channel go

我试图更好地了解 golang 通道。在阅读本文时,我正在研究非阻塞发送,并提出了以下代码:

package main
import (
    "fmt"
    "time"
)

func main() {
    stuff := make(chan int)
    go func(){
        for i := 0; i < 5; i ++{
            select {
            case stuff <- i:
                fmt.Printf("Sent %v\n", i)
            default:
                fmt.Printf("Default on %v\n", i)
            }
        }
        println("Closing")
        close(stuff)
    }()
    time.Sleep(time.Second)
    fmt.Println(<-stuff)
    fmt.Println(<-stuff)
    fmt.Println(<-stuff)
    fmt.Println(<-stuff)
    fmt.Println(<-stuff)
}
Run Code Online (Sandbox Code Playgroud)

这将打印:

Default on 0
Default on 1
Default on 2
Default on 3
Default on 4
Closing
0
0
0
0
0
Run Code Online (Sandbox Code Playgroud)

虽然我确实明白只有0s 会被打印,但我不太明白为什么第一次发送仍然会触发default选择的分支?

在这种情况下,选择行为背后的逻辑是什么?

Go Playground 中的示例

Jim*_*imB 5

您永远不会向 发送任何值stuff,而是在执行语句中的任何接收操作之前执行所有默认情况fmt.Println。如果没有其他操作可以继续,则立即执行该default情况,这意味着您的循环将尽快执行并返回。

您想阻止循环,因此不需要案例default。您也不需要close最后的,因为您不依赖封闭通道来解锁接收或中断子句range

stuff := make(chan int)
go func() {
    for i := 0; i < 5; i++ {
        select {
        case stuff <- i:
            fmt.Printf("Sent %v\n", i)
        }
    }
    println("Closing")
}()
time.Sleep(time.Second)
fmt.Println(<-stuff)
fmt.Println(<-stuff)
fmt.Println(<-stuff)
fmt.Println(<-stuff)
fmt.Println(<-stuff)
Run Code Online (Sandbox Code Playgroud)

https://play.golang.org/p/k2rmRDP38f

另请注意,最后的“Sent”和“Closing”行不会被打印,因为没有其他同步等待 goroutine 完成,但这不会影响此示例的结果。