我花了很多时间来调试为什么我的频道不接受任何东西。我设法将问题本地化为与裸返回的命名返回值范围有关的问题。以下代码显示了该问题。
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)]:
...
我无法理解为什么渠道应该为零。我尝试使用原始值进行类似的赋值,它返回了我期望的结果。为什么渠道无效?这里有什么阴影?
答案 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