14.10 Select 语句

select 语句根据一组一个或多个(发送或接收)通道操作进行分支。它类似于 switch 语句,但是在 select 语句中,所有情况均涉及通信操作。

select { /* communication clauses */ }

通信案例子句的语法如下:

case SendStatement : StatementList

case ReceiveStatement : StatementList

发送语句是 Go 中的复合语句之一,例如 ch<- v。接收语句可以有以下三种形式:

  • 单独用作表达式语句的接收操作,例如 <-ch。

  • 在赋值语句中使用的接收操作,例如 arr[2] = <-ch。

  • 在短变量声明语句中使用的接收操作,例如 x := <-ch。

与 switch 语句类似,select 语句也可以有可选的 default case:

default : StatementList

下面是 select 语句的简单用法示例:

package main

import "fmt"

func lucasSequence(ch chan int, done chan bool) {
    a, b := 2, 1                       // 卢卡斯数的产生方式与斐波那契数的产生方式相同。唯一的区别是,前两个数字是2和1,而不是斐波那契数列的1和1

    for {
        select {                       // 注意选择语句在无限for循环中的使用
        case ch <- a:                  // 一个带有SendStatement的case子句
            a, b = b, a+b              // 第n个Lucas/Fibonacci数是第(n-1)个和第(n-2)个数之和
        case <-done:                   // 一个带有ReceiveStatement的case子句
            return
        }
    }
}

func main() {
    ch := make(chan int)
    done := make(chan bool)

    go func() {
        for i := 1; i <= 10; i++ {
            fmt.Println(i, "->", <-ch)
        }
        done <- true
    }()

    lucasSequence(ch, done)
}

注意这个例子中通道和 go 协程的惯用法。大多数现代编程语言都有类似生成器和协程等的结构(例如 yield 语句)。Go 没有。Go 使用通道来完成类似的任务,还有其他事情。在这个例子中,例如 lucasSequence 可以视为一个生成器函数。

最后更新于