Golang:无法在频道上发送

Flo*_*mak 1 concurrency channel go

为什么它不在通道上发送并阻止执行?我怎样才能使这个星座工作,以便我可以向其中发送信号MoneyDive()并继续执行?

package main

import (
    "fmt"
)

type Quack func(ch chan bool)

type DagobertDuck struct {
    quack Quack
}

func (self *DagobertDuck) MoneyDive() {
    ch := make(chan bool)
    self.quack(ch)
    b := <-ch
    if b {
        fmt.Println("true")
    } else {
        fmt.Println("false")
    }
}

func mockQuack(ch chan bool) {
    fmt.Println("mockQuack start")
    ch <- true
    fmt.Println("mockQuack done")
}

func main() {
    dd := DagobertDuck{quack: mockQuack}
    dd.MoneyDive()
}
Run Code Online (Sandbox Code Playgroud)

https://play.golang.org/p/1omlb7u6-A

icz*_*cza 5

因为你有一个无缓冲的通道,如果有另一个 goroutine 准备从它接收,你只能在无缓冲的通道上发送一个值而不会阻塞。

由于您只有 1 个 goroutine,它会被阻塞。解决方案很简单:Quack.quack()在一个新的 goroutine 中启动你的方法:

go self.quack(ch)
Run Code Online (Sandbox Code Playgroud)

然后输出(在Go Playground上试试):

mockQuack start
mockQuack done
true
Run Code Online (Sandbox Code Playgroud)

另一种选择是不启动一个新的 goroutine 而是创建一个缓冲通道,这样它就可以保存一些值,而没有任何接收器准备好从它接收:

ch := make(chan bool, 1) // buffered channel, buffer for 1 value
Run Code Online (Sandbox Code Playgroud)

这创建了一个通道,它能够“存储”一个值,而没有任何接收器准备好接收它。通道上的第二次发送也会阻塞,除非首先从它接收到值(或者接收器准备好从它接收值)。

Go Playground上试试这个缓冲频道版本。

规范中的相关部分:发送语句:

在通信开始之前评估通道和值表达式。通信阻塞,直到发送可以继续。如果接收器准备好,则可以继续在无缓冲通道上发送。如果缓冲区中有空间,则可以继续在缓冲通道上发送。关闭通道上的发送会导致运行时恐慌。在nil通道上发送永远阻塞。

笔记:

根据您打印true或接收到的值false。这可以用一行完成,没有if语句:

fmt.Println(b)
Run Code Online (Sandbox Code Playgroud)

你甚至可以去掉b局部变量,并立即打印接收到的值:

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

另外我假设您使用频道是因为您想使用它们,但在您的情况下mockQuack()可以简单地返回bool值,而不使用频道。