go教程6
关闭信道和使用 for range 遍历信道
数据发送方可以关闭信道,通知接收方这个信道不再有数据发送过来。
当从信道接收数据时,接收方可以多用一个变量来检查信道是否已经关闭。
v, ok := <- ch
上面的语句里,如果成功接收信道所发送的数据,那么 ok
等于 true。而如果 ok
等于 false,说明我们试图读取一个关闭的通道。从关闭的信道读取到的值会是该信道类型的零值。例如,当信道是一个 int
类型的信道时,那么从关闭的信道读取的值将会是 0
。
package main
import(
"fmt"
)
funcproducer(
chnl
chanint)
{
for
i
:=0;
i
<10;
i
++{
chnl
<-i
}
close(
chnl
)
}
funcmain()
{
ch
:=make(chan
int)
go
producer(
ch
)
for
{
v
,ok
:=<-
ch
if
ok
==false
{
break
}
fmt
.Println("Received ",v
,ok
)
}
}
在上述的程序中,producer
协程会从 0 到 9 写入信道 chn1
,然后关闭该信道。主函数有一个无限的 for 循环(第 16 行),使用变量 ok
(第 18 行)检查信道是否已经关闭。如果 ok
等于 false,说明信道已经关闭,于是退出 for 循环。如果 ok
等于 true,会打印出接收到的值和 ok
的值。
Received 0 true
Received 1 true
Received 2 true
Received 3 true
Received 4 true
Received 5 true
Received 6 true
Received 7 true
Received 8 true
Received 9 true
for range 循环用于在一个信道关闭之前,从信道接收数据。
接下来我们使用 for range 循环重写上面的代码。
package main
import(
"fmt"
)
funcproducer(
chnl
chanint)
{
for
i
:=0;
i
<10;
i
++{
chnl
<-i
}
close(
chnl
)
}
funcmain()
{
ch
:=make(chan
int)
go
producer(
ch
)
for
v
:=range
ch
{
fmt
.Println("Received ",v
)
}
}
在第 16 行,for range 循环从信道 ch
接收数据,直到该信道关闭。一旦关闭了 ch
,循环会自动结束,如果不关闭,for range循环会一直把线程卡死。该程序会输出:
Received 0
Received 1
Received 2
Received 3
Received 4
Received 5
Received 6
Received 7
Received 8
Received 9
我们可以使用 for range 循环,重写信道的另一个示例这一节里面的代码,提高代码的可重用性。
如果你仔细观察这段代码,会发现获得一个数里的每位数的代码在 calcSquares
和 calcCubes
两个函数内重复了。我们将把这段代码抽离出来,放在一个单独的函数里,然后并发地调用它。
package main
import(
"fmt"
)
funcdigits(
number
int,dchnl
chanint)
{
for
number
!=0
{
digit
:=number
%10
dchnl
<-digit
number
/=10
}
close(
dchnl
)
}
funccalcSquares(
number
int,squareop
chanint)
{
sum
:=0
dch
:=make(chan
int)
go
digits(
number
,dch
)
for
digit
:=range
dch
{
sum
+=digit
*digit
}
squareop
<-sum
}
funccalcCubes(
number
int,cubeop
chanint)
{
sum
:=0
dch
:=make(chan
int)
go
digits(
number
,dch
)
for
digit
:=range
dch
{
sum
+=digit
*digit
*digit
}
cubeop
<-sum
}
funcmain()
{
number
:=589
sqrch
:=make(chan
int)
cubech
:=make(chan
int)
go
calcSquares(
number
,sqrch
)
go
calcCubes(
number
,cubech
)
squares
,cubes
:=<-
sqrch
,<-
cubech
fmt
.Println("Final output",squares
+cubes
)
}
上述程序里的 digits
函数,包含了获取一个数的每位数的逻辑,并且 calcSquares
和 calcCubes
两个函数并发地调用了 digits
。当计算完数字里面的每一位数时,第 13 行就会关闭信道。calcSquares
和 calcCubes
两个协程使用 for range 循环分别监听了它们的信道,直到该信道关闭。程序的其他地方不变,该程序同样会输出:
Final output 1536
本文来自博客园,作者:易先讯,转载请注明原文链接:https://www.cnblogs.com/gongxianjin/p/17981800