gopl-zh.github.com/ch8/ch8-04-3.md

55 lines
2.6 KiB
Markdown
Raw Normal View History

2016-02-15 03:06:34 +00:00
### 8.4.3. 单方向的Channel
2016-01-04 06:26:54 +00:00
2016-10-05 05:42:01 +00:00
随着程序的增长人们习惯于将大的函数拆分为小的函数。我们前面的例子中使用了三个goroutine然后用两个channels来连接它们它们都是main函数的局部变量。将三个goroutine拆分为以下三个函数是自然的想法
2016-01-04 06:26:54 +00:00
```Go
func counter(out chan int)
func squarer(out, in chan int)
func printer(in chan int)
```
2016-10-05 05:42:01 +00:00
其中计算平方的squarer函数在两个串联Channels的中间因此拥有两个channel类型的参数一个用于输入一个用于输出。两个channel都拥有相同的类型但是它们的使用方式相反一个只用于接收另一个只用于发送。参数的名字in和out已经明确表示了这个意图但是并无法保证squarer函数向一个in参数对应的channel发送数据或者从一个out参数对应的channel接收数据。
2016-01-04 06:26:54 +00:00
2016-09-30 13:56:19 +00:00
这种场景是典型的。当一个channel作为一个函数参数时它一般总是被专门用于只发送或者只接收。
2016-01-04 06:26:54 +00:00
2016-02-15 03:06:34 +00:00
为了表明这种意图并防止被滥用Go语言的类型系统提供了单方向的channel类型分别用于只发送或只接收的channel。类型`chan<- int`intchannel`<-chan int`intchannel`<-`chanchannel
2016-01-04 06:26:54 +00:00
2016-02-15 03:06:34 +00:00
因为关闭操作只用于断言不再向channel发送新的数据所以只有在发送者所在的goroutine才会调用close函数因此对一个只接收的channel调用close将是一个编译错误。
2016-01-04 06:26:54 +00:00
2016-02-15 03:06:34 +00:00
这是改进的版本这一次参数使用了单方向channel类型
2016-01-04 06:26:54 +00:00
2016-01-21 02:39:06 +00:00
<u><i>gopl.io/ch8/pipeline3</i></u>
2016-01-04 06:26:54 +00:00
```Go
func counter(out chan<- int) {
for x := 0; x < 100; x++ {
out <- x
}
close(out)
}
func squarer(out chan<- int, in <-chan int) {
for v := range in {
out <- v * v
}
close(out)
}
func printer(in <-chan int) {
for v := range in {
fmt.Println(v)
}
}
func main() {
naturals := make(chan int)
squares := make(chan int)
go counter(naturals)
go squarer(squares, naturals)
printer(squares)
}
```
2017-05-03 02:48:04 +00:00
调用counternaturalsnaturals的类型将隐式地从chan int转换成chan<- intprinter(squares)`<-chan int`channelchannelchannel`chan<- int`channel`chan int`channel
2016-01-04 06:26:54 +00:00
2016-01-02 14:05:49 +00:00