package main import "fmt" func adder() func(int) int { sum := 0 return func(x int) int { sum += x return sum } } func main() { pos, neg := adder(), adder() for i := 0; i < 10; i++ { fmt.Println( pos(i), neg(-2*i), ) } }
zzh@ZZHPC:/zdata/MyPrograms/Go/testing$ go run main.go 0 0 1 -2 3 -6 6 -12 10 -20 15 -30 21 -42 28 -56 36 -72 45 -90
Go functions may be closures. A closure is a function value that references variables from outside its body. The function may access and assign to the referenced variables; in this sense the function is "bound" to the variables.
For example, the adder
function returns a closure. Each closure is bound to its own sum
variable.
Why do you need closures? They have many uses, but writing middleware for web applications is one of the most well-known.
Web application middleware are functions that can be added to the web application’s request/response pipeline to handle common tasks like logging or access control. In Go, it’s common to implement web application middleware using closures.
To see how closure is being used, here’s a simple web application that shows “Hello World” when you access the web application at /hello:
package main import ( "fmt" "net/http" ) func main() { http.HandleFunc("/hello", hello) http.ListenAndServe(":8000", nil) } func hello(w http.ResponseWriter, r *http.Request) { fmt.Fprintln(w, "Hello World") }
The web application is simple. It has a handler named hello , which is used as a parameter in the HandleFunc function to set up a handler for the web application.
If you want to log to screen or file each time a handler is called, and you also want to know how long the handler takes to execute its tasks, you could create a small function that allows you to log and call that function in each handler. It’s tedious, but it works. Logging the time, however, is even messier because you need to insert code at the beginning and run some deferred code to get the end timing to figure out the execution time.
Alternatively, you can create a piece of middleware that will do both:
package main import ( "fmt" "log" "net/http" "reflect" "runtime" "time" ) func main() { http.HandleFunc("/hello", logger(hello)) http.ListenAndServe(":8000", nil) } func hello(w http.ResponseWriter, r *http.Request) { fmt.Fprintln(w, "Hello World") } func logger(f http.HandlerFunc) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { start := time.Now() f(w, r) end := time.Now() name := runtime.FuncForPC(reflect.ValueOf(f).Pointer()).Name() log.Printf("%s (%v)", name, end.Sub(start)) } }
Run main.go in a terminal, visit localhost:8000/hello in the browser, you'll see the log informaion added by the logger middleware function:
zzh@ZZHPC:/zdata/MyPrograms/Go/testing$ go run main.go 2023/10/01 09:10:41 main.hello (5.27µs)
func FuncForPC ¶
FuncForPC returns a *Func describing the function that contains the given program counter address, or else nil.
If pc represents multiple functions because of inlining, it returns the *Func describing the innermost function, but with an entry of the outermost function.
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)
· winform 绘制太阳,地球,月球 运作规律