在 go 语言中,函数是一等公民。函数既可以作为参数传入,也可以作为返回值返回。
go 语言的函数式编程最典型的例子就是 闭包。
闭包是什么呢?
简单讲,闭包就是指有权访问另一个函数作用域中的变量的函数。
它由两部分构成:函数,以及创建该函数的环境。环境由闭包创建时在作用域中的任何局部变量组成。
外部函数调用之后其变量对象本应该被销毁,但闭包的存在使我们仍然可以访问外部函数的变量对象,这就是闭包的重要概念。

package main
import "fmt"
func fib() func() int {
a,b := 0,1
return func() int {
b,a = a+b,b
return b
}
}
func main() {
f := fib()
for i := 0 ; i < 20;i++ {
fmt.Printf("%d ",f())
}
}
// 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987 1597 2584 4181 6765 10946
为函数生成接口
上面的例子中,f() 是每执行一遍的话 ,会生成一个新的斐波那契数。可以把他实现成为一个read的接口。那么就可以使用 scanner.Scan()。像读文件一样打印斐波那契数列。
package main
import (
"bufio"
"fmt"
"io"
"strings"
)
func fib() IntGen {
a,b := 0,1
return func() int {
b,a = a+b,b
return b
}
}
type IntGen func() int
func (g IntGen) Read(p []byte) (n int,err error) {
next := g()
if next > 1000000 {
return 0,io.EOF
}
s := fmt.Sprintf("%d ",next)
return strings.NewReader(s).Read(p)
}
func PrintFib(read io.Reader) {
scanner := bufio.NewScanner(read)
for scanner.Scan() {
fmt.Println(scanner.Text())
}
}
func main() {
f := fib()
PrintFib(f)
}
传入函数来解决问题
假设现在有一个遍历二叉数的函数。他只是做了打印的操作,那能否使用之前的所学到的知识,再丰富其功能呢。
func (t *TreeNode) Traverse() {
if t == nil {
return
}
t.Left.Traverse()
fmt.Println(t.Val)
t.Right.Traverse()
}
用闭包改造后,不仅可以打印出每一个值,而且可以打印出一共有多少个节点。
func (t *TreeNode) Traverse() {
cnt := 0
t.TraverseFunc(func(node *TreeNode) {
fmt.Printf("%d ",node.Val)
cnt ++
})
fmt.Println("\nNode cnt is",cnt)
}
func (t *TreeNode) TraverseFunc(f func (*TreeNode) ) {
if t == nil {
return
}
t.Left.TraverseFunc(f)
f(t)
t.Right.TraverseFunc(f)
}
网友评论