go中一个通道使用两个箭头写入另一个通道是什么意思

kSe*_*Set 1 concurrency go channels

这是 Go 中的 Concurrency 一书中的代码示例。在 select 块中是以下语句

case takeStream <- <- valueStream:
Run Code Online (Sandbox Code Playgroud)

看不懂双箭头是干什么的,文中也没有解释。当我将其替换为时,输出会发生变化

case takeStream <- valueStream:
Run Code Online (Sandbox Code Playgroud)

所以这显然是必要的

功能齐全:

func take(done<- chan interface{}, valueStream <- chan interface{}, num int) <- chan interface{}{
    takeStream := make ( chan interface{})
    go func() {
        defer close(takeStream)
        for i := 0; i < num; i ++ {
            select {
            case <- done :
                return
            case takeStream <- <- valueStream:
            }
        }
    }()

    return takeStream
}
Run Code Online (Sandbox Code Playgroud)

编辑:如果我理解正确,扩展出来的语句将是

i := 5
valueStream <- i
tmp <- valueStream
takeStream <- tmp
Run Code Online (Sandbox Code Playgroud)

所以

takeStream <- <- valuesStream
Run Code Online (Sandbox Code Playgroud)

是捷径

这解释了为什么当我打电话

fmt.Println(<-takeStream)
Run Code Online (Sandbox Code Playgroud)

我得到了时髦的数字——大概是 valueStream 的一些数字表示

谢谢!

icz*_*cza 7

takeStream <- <- valueStream是接收操作(接收操作符)和发送语句的串联。

接收运算符是一元运算符,因此具有最高优先级 ( Spec: Operators ),而 send 语句是一个语句,不属于运算符层次结构。因此,c1 <- <- c2与 相同c1 <- (<-c2)

所以你的例子是一样的:

takeStream <- (<-valueStream)
Run Code Online (Sandbox Code Playgroud)

(请注意,任何其他解释都没有任何意义。)

和规范:发送语句:

在通信开始之前评估通道和值表达式。

要发送的值必须在发送之前进行评估。因此,您的示例首先从 接收一个值valueStream,然后将该值发送到takeStream...

...或者如果这个发送语句(和接收操作符)独立存在。

当在select语句中用作a的通信操作之一时case,会发生以下情况:

引自Spec: Select 语句:

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

  1. 对于语句中的所有情况,接收操作的通道操作数以及发送语句的通道和右侧表达式在进入“选择”语句时按源顺序仅计算一次。结果是一组要接收或发送的通道,以及要发送的相应值。无论选择哪个(如果有)通信操作进行,该评估中的任何副作用都会发生。带有简短变量声明或赋值的 RecvStmt 左侧的表达式尚未计算。

[...]

所以当你有这个时:

select {
case <- done :
    return
case takeStream <- <- valueStream:
}
Run Code Online (Sandbox Code Playgroud)

然后<-valueStream进行评估(从 接收值valueStream)。如果操作是阻塞的,那么整个select将阻塞(即使done是关闭的并因此准备好接收)。

一旦从 接收到一个值valueStream,只有到那时才决定是否可以在 上发送该值takeStream,以及case如果其他情况也可以继续进行,是否选择此选项。

  1. 如果可以进行一个或多个通信,则通过统一伪随机选择选择可以进行的单个通信。否则,如果存在默认情况,则选择该情况。如果没有默认情况,“select”语句会阻塞,直到至少有一个通信可以继续。