管道的概念
在Go里,并没有正式的管道的定义,它只是众多并发程序其中的一个。通俗来讲,一个管道是一系列由通道连接的阶段,每个阶段都是一组运行着同样函数的goroutine。在每个阶段里,goroutine在干着
一个用来学习的例子
下面我们将展开一个简单的管道例子,来阐述其中的思想和技术,后面会有实际的例子。
make
make也是用于内存分配的,但是和new不同,它只用于chan、map以及切片的内存创建,而且它返回的类型就是这三个类型本身,而不是他们的指针类型,因为这三种类型就是引用类型,所以就没有必要返回他们的指针了。
注意,因为这三种类型是引用类型,所以必须得初始化,但是不是置为零值,这个和new是不一样的。
1 |
|
从函数声明中可以看到,返回的还是该类型。
平方函数
直接看代码中注释。
// 要想run,必须package main,默认是文件夹目录名,要更改一下
package main
import "fmt"
// 设想一个拥有三个阶段的管道
/*
* First Stage: gen
* params: 一个以逗号分隔的整数列表,数量不限
* return: 一个通道,包含参数中整数列表的通道
*/
func gen(nums ... int) <-chan int {
out := make(chan int)
// 通过一个goroutine来将参数中的每个整数发送到通道中去。
go func() {
for _, n := range nums {
out <- n
}
close(out) // close方法作为上面的for循环的终止条件,不能省略。
}()
return out
}
/*
* Second Stage: sq
* params: 一个包含参数中整数列表的通道
* return: 一个包含将参数通道中每个整数平方后的列表的通道
* note: 因为参数和返回值的类型都是相同的整型通道,所以可以反复嵌套该方法。
*/
func sq(in <-chan int) <-chan int {
out := make(chan int)
go func() {
for n := range in {
out <- n * n // 平方
}
close(out)
}()
return out
}
/*
* Final Stage: main
* 是一个main函数,没有参数也没有返回值,它相当于客户端调用
*/
func main() {
c := gen(2, 3) // 建立通道
out := sq(c) // 通道处理
// 上面传入两个值2和3,那么这里就要对应的消费两次输出
fmt.Println(<-out)
fmt.Println(<-out)
// 嵌套sq
for n := range sq(sq(gen(1, 2, 4, 5))) {
fmt.Println(n)
}
}
// output:
// 4
// 9
// 1
// 16
// 256
// 625