通道返回裸返回时为零

时间:2018-07-19 09:33:25

标签: go

我花了很多时间来调试为什么我的频道不接受任何东西。我设法将问题本地化为与裸返回的命名返回值范围有关的问题。以下代码显示了该问题。

package main

import (
    "log"
    "sync"
)

var receiver chan int

func Setup() (receiver chan int) {
    receiver = make(chan int)
    return
}

//func Setup() (chan int) {
//  receiver = make(chan int)
//  return receiver
//}

func Launch(j int){

    for i := 0; i < j; i++ {
        receiver <- i
    }

}

func main() {

    var wg sync.WaitGroup
    wg.Add(10)

    rcvr := Setup()

    go func() {
        for r := range rcvr {
            log.Println(r)
            wg.Done()
        }
    }()

    Launch(10)

    wg.Wait()

 }

运行此代码会产生下一个错误

fatal error: all goroutines are asleep - deadlock!

goroutine 1 [chan send (nil chan)]:

...

我无法理解为什么渠道应该为零。我尝试使用原始值进行类似的赋值,它返回了我期望的结果。为什么渠道无效?这里有什么阴影?

1 个答案:

答案 0 :(得分:3)

修改:修改后的代码:

现在您正在使用2个完全不同的频道。 main()中有一个频道,您尝试从中使用(for range)。并且您还有另一个通道(全局receiver变量,您从不会为其分配任何值,因此它仍为nil。并且在nil通道上发送值将永远被阻止(请参见{{3} })。

因此,您已经拥有了:Launch()被阻止在nil通道上发送,并且您的main() goroutine等待它启动的另一个goroutine,后者等待{ {1}}没有人向其发送任何内容的通道。

一种简单的方法是将频道传递到您在rcvr中创建的Launch(),并摆脱全局变量:

main()

调用时:

func Launch(j int, receiver chan int) {
    for i := 0; i < j; i++ {
        receiver <- i
    }
}

然后它将起作用,输出将是(在How does a non initialized channel behave?上尝试):

Launch(10, rcvr)

原始答案如下:

问题在于,在存储2009/11/10 23:00:00 0 2009/11/10 23:00:00 1 2009/11/10 23:00:00 2 2009/11/10 23:00:00 3 2009/11/10 23:00:00 4 2009/11/10 23:00:00 5 2009/11/10 23:00:00 6 2009/11/10 23:00:00 7 2009/11/10 23:00:00 8 2009/11/10 23:00:00 9 返回的频道时,您会在主目录中使用Go Playground

Setup()

这不会为您的全局receiver := Setup() 变量赋值,但是会创建一个遮盖全局变量的新局部变量,而您的receiver函数将使用该局部变量变量。但是您的main()函数将使用全局变量(看不到Launch()的局部变量)。

使用简单的short variable declaration,一切都会好起来的:

main