为了账号安全,请及时绑定邮箱和手机立即绑定

选择单个案例块,添加默认值:unblocks

选择单个案例块,添加默认值:unblocks

Go
红颜莎娜 2022-03-02 19:27:18
在用这样的东西测试一些代码时:// ch := make(chan error)for {    select {      case <- ch:           println("here")    }}我注意到,如果我不添加default代码块:for {    select {       case <- ch:            println("here")       default:    }}如果需要该块,最好使用range,例如:for {    for _ = range <- ch {        println("here")    }}或者在这种情况下使用selectover有什么区别/优势吗?range
查看完整描述

3 回答

?
慕姐4208626

TA贡献1852条经验 获得超7个赞

1-当您处理一个频道时,可以使用for,

考虑这个工作代码(The Go Playground):


package main


import "fmt"


func main() {

    ch := make(chan int, 2)

    ch <- 1

    ch <- 2

    close(ch)

    for range ch {

    }

    fmt.Println("Done.")

}

这将清空通道。

注意:您应该close使用通道或使用break语句来完成该循环。


2- 当您处理更多可能使用的频道时select,就像这样(The Go Playground):


for {

    select {

    case <-pause:

        fmt.Println("pause")

        select {

        case <-play:

            fmt.Println("play")

        case <-quit:

            wg.Done()

            return

        }

    case <-quit:

        wg.Done()

        return

    default:

        work()

    }

}

3- 使用 nil 和封闭通道(The Go Playground):


package main


import "fmt"


func main() {

    var quit chan struct{} // nil


    select {

    case <-quit:

        fmt.Println("1")

    default:

        fmt.Println("2") // This runs

    }


    quit = make(chan struct{}, 1)


    select {

    case <-quit:

        fmt.Println("10")

    default:

        fmt.Println("20") // This runs

    }


    quit <- struct{}{} // send


    select {

    case <-quit:

        fmt.Println("100") // This runs

    default:

        fmt.Println("200")

    }


    close(quit)


    select {

    case <-quit:

        fmt.Println("1000") // This runs

    default:

        fmt.Println("2000")

    }


    select {

    case <-quit:

        fmt.Println("10000") // This runs

    default:

        fmt.Println("20000")

    }

}

输出:


2

20

100

1000

10000

选择语句


“选择”语句选择一组可能的发送或接收操作中的哪一个将继续。它看起来类似于“switch”语句,但所有案例都涉及通信操作。


具有 RecvStmt 的案例可以将 RecvExpr 的结果分配给一个或两个变量,这些变量可以使用短变量声明来声明。RecvExpr 必须是(可能带括号的)接收操作。最多可以有一个默认案例,它可能出现在案例列表中的任何位置。


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


对于语句中的所有情况,在输入“select”语句时,接收操作的通道操作数以及发送语句的通道和右侧表达式仅按源顺序计算一次。结果是一组要接收或发送到的通道,以及要发送的相应值。无论选择哪种(如果有)通信操作进行,该评估中的任何副作用都会发生。RecvStmt 左侧的带有短变量声明或赋值的表达式尚未计算。如果一个或多个通信可以进行,则通过统一的伪随机选择选择一个可以进行的通信。否则,如果存在默认情况,则选择该情况。如果没有默认情况,则“选择” 语句块,直到至少有一个通信可以进行。除非所选案例是默认案例,否则执行相应的通信操作。如果所选用例是带有短变量声明或赋值的 RecvStmt,则计算左侧表达式并分配接收到的值(或多个值)。执行所选案例的语句列表。由于 nil 通道上的通信永远无法进行,因此只有 nil 通道且没有默认案例的选择会永远阻塞。执行所选案例的语句列表。由于 nil 通道上的通信永远无法进行,因此只有 nil 通道且没有默认案例的选择会永远阻塞。执行所选案例的语句列表。由于 nil 通道上的通信永远无法进行,因此只有 nil 通道且没有默认案例的选择会永远阻塞。


查看完整回答
反对 回复 2022-03-02
?
斯蒂芬大帝

TA贡献1827条经验 获得超8个赞

在您的情况下,似乎一个简单的循环就足够了:

for _ = range ch {
    fmt.Println("drain")}

如果您有多个goroutines 需要处理,则 Select 是必需的。巡回赛有一个range 和 close的例子。

另一种情况select是幂等通道关闭: https: //play.golang.org/p/_Ol42BvuuS


查看完整回答
反对 回复 2022-03-02
?
慕工程0101907

TA贡献1887条经验 获得超5个赞

如果 select 中只有一种情况,那么最好use for range instead of for { select {} } (gosimple)使用S1000golint 检查。

for range代码就像:

for range ch {
    fmt.Println("here")}



查看完整回答
反对 回复 2022-03-02
  • 3 回答
  • 0 关注
  • 481 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
微信客服

购课补贴
联系客服咨询优惠详情

帮助反馈 APP下载

慕课网APP
您的移动学习伙伴

公众号

扫描二维码
关注慕课网微信公众号