Go闭包教程展示了如何在Golang中使用闭包。
Go函数是一等公民。函数可以分配给变量、存储在集合中、动态创建和删除,或作为参数传递。
嵌套函数,也称为内部函数,是在另一个函数中定义的函数。匿名函数是未绑定到标识符的函数定义。匿名函数通常是传递给高阶函数的参数
$ go version go version go1.18.1 linux/amd64
我们使用Go版本1.18。
去闭包
Go闭包是一个匿名嵌套函数,它保留对在闭包主体外定义的变量的绑定。
闭包可以拥有自己独特的状态。当我们创建函数的新实例时,状态就会变得孤立。
package main import "fmt" func main() { sum := func(a, b, c int) int { return a + b + c }(3, 5, 7) fmt.Println("5+3+7 =", sum) }
我们创建了一个添加三个值的匿名函数。我们在函数定义后立即将三个参数传递给该函数。
Go闭包简单例子
在下面的例子中,我们定义了一个简单的闭包。
package main import "fmt" func intSeq() func() int { i := 0 return func() int { i++ return i } } func main() { nextInt := intSeq() fmt.Println(nextInt()) fmt.Println(nextInt()) fmt.Println(nextInt()) fmt.Println(nextInt()) nextInt2 := intSeq() fmt.Println(nextInt2()) }
我们有intSeq
函数,它生成一个整数序列。它返回一个递增i
变量的闭包。
func intSeq() func() int {
intSeq
是一个函数,它返回一个重新运行整数的函数。
func intSeq() func() int { i := 0 return func() int { i++ return i } }
函数中定义的变量具有局部函数作用域。但是,在这种情况下,即使在intSeq
函数返回后,闭包也绑定到i
变量。
nextInt := intSeq()
我们调用intSeq
函数。它返回一个函数,该函数将增加一个计数器。返回的函数关闭变量i
以形成闭包。闭包绑定到nextInt
名称。
fmt.Println(nextInt()) fmt.Println(nextInt()) fmt.Println(nextInt()) fmt.Println(nextInt())
我们多次调用闭包。
nextInt2 := intSeq() fmt.Println(nextInt2())
intSeq
函数的下一次调用返回一个新的闭包。这个新的闭包有自己独特的状态。
$ go run closure.go 1 2 3 4 1
Go闭包斐波那契示例
斐波那契数列是一个值序列,每个数字都是前面两个数字的总和,从0和1开始。序列的开头是:0、1、1、2、3、5、8、13,21,34,55,89,144…
package main import "fmt" func fibonacci() func() int { a := 0 b := 1 return func() int { a, b = b, a+b return b-a } } func main() { f := fibonacci() for i := 0; i < 10; i++ { fmt.Println(f()) } }
这是使用闭包实现的斐波那契数列。如果fibonacci
函数未保留a
和b
的值,则计算将无法进行。
$ go run fibonacci.go 0 1 1 2 3 5 8 13 21 34
Go闭包中间件
中间件是在向服务器发出请求的生命周期中执行的函数。中间件通常用于日志记录、错误处理或数据压缩。
在Go中,中间件通常是在闭包的帮助下创建的。
package main import ( "fmt" "log" "net/http" "time" ) func main() { http.HandleFunc("/now", logDuration(getTime)) fmt.Println("Server started at port 8080") log.Fatal(http.ListenAndServe(":8080", nil)) } func logDuration(f func(http.ResponseWriter, *http.Request)) func(http.ResponseWriter, *http.Request) { return func(w http.ResponseWriter, r *http.Request) { start := time.Now() f(w, r) end := time.Now() fmt.Println("The request took", end.Sub(start)) } } func getTime(w http.ResponseWriter, r *http.Request) { now := time.Now() _, err := fmt.Fprintf(w, "%s", now) if err != nil { log.Fatal(err) } }
我们有一个简单的HTTP服务器,它用当前日期时间响应/now
。
http.HandleFunc("/now", logDuration(getTime))
在Go中,函数可以作为参数传递给其他函数。我们将logDuration
函数包装在getTime
函数之上。
func logDuration(f func(http.ResponseWriter, *http.Request)) func(http.ResponseWriter, *http.Request) { return func(w http.ResponseWriter, r *http.Request) { start := time.Now() f(w, r) end := time.Now() fmt.Println("The request took", end.Sub(start)) } }
logDuration
函数返回一个获取当前时间的闭包,调用原始函数,获取结束时间,并打印出请求的持续时间。闭包对于处理函数内部实际发生的事情是不可知的。
在本教程中,我们使用了Golang中的闭包。
列出所有Go教程。