点击阅读更多查看文章内容
Go语言编程思想2——函数式编程
函数是一等公民:参数,变量,返回值都可以是函数
高阶函数:函数的参数还可以是函数
函数->闭包
“正统”函数式编程
不可变性:不能有状态,只有常量和函数
函数只能有一个参数
闭包
下例中,adder()的返回值就是一个函数体,其中v为函数体的局部变量。sum是函数所处的一个环境,是自由变量,编译器会将函数体连接到自由变量,在本例中sum是int型,实际上sum也可以是一个结构继续连接到其他变量,最终函数体会连接到全部的变量组成上图中树的形状,形成闭包。
返回值是一个闭包,不仅是func那段代码,而是这个函数以及对sum的引用,以及保存的sum变量
1 2 3 4 5 6 7 8 9 10 11 12 13 14 func adder () func (int ) int { sum := 0 return func (v int ) int { sum += v return sum } } func main () { a := adder() for i := 0 ; i < 10 ; i++ { fmt.Printf("0+1+...+%d=%d\n" , i, a(i)) } }
“正统”函数式编程,不存在状态(没有变量sum)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 type iAdder func (int ) (int , iAdder)func adder2 (base int ) iAdder { return func (v int ) (int , iAdder) { return base + v, adder2(base + v) } } func main () { a := adder2(0 ) for i := 0 ; i < 10 ; i++ { var s int s, a = a(i) fmt.Printf("0+1+...+%d=%d\n" , i, s) } }
例一:斐波那契数列 1 2 3 4 5 6 7 func fibonacci () func () int { a, b := 0 , 1 return func () int { a, b = b, a+b return a } }
例二:为函数实现接口 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 func fibonacci () intGen { a, b := 0 , 1 return func () int { a, b = b, a+b return a } } type intGen func () int func (g intGen) Read(p []byte ) (n int , err error ) { next := g() if next>10000 { return 0 , io.EOF } s := fmt.Sprintf("%d\n" , next) return strings.NewReader(s).Read(p) } func printFileContents (reader io.Reader) { scanner :=bufio.NewScanner(reader) for scanner.Scan(){ fmt.Println(scanner.Text()) } } func main () { f := fibonacci() printFileContents(f) }
例三:使用函数来遍历二叉树 将之前的print()换为一个函数,可以实现更多的功能
修改前:
1 2 3 4 5 6 7 8 func (node *Node) Traverse() { if node == nil { return } node.Left.Traverse() node.print () node.Right.Traverse() }
修改后
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 func (node *Node) Traverse() { node.TraverseFunc(func (node *Node) { node.Print() }) fmt.Println() } func (node *Node) TraverseFunc(f func (*Node) ) { if node == nil { return } node.Left.TraverseFunc(f) f(node) node.Right.TraverseFunc(f) }
将之前的打印换为一个函数,可以实现更多的功能 例如:结点计数
1 2 3 4 nodeCount:=0 root.TraverseFunc(func (node *tree.Node) { nodeCount++ })
go语言闭包的应用
更为自然,不需要修饰如何访问自由变量
没有Lambda表达式,但是有匿名函数