ZhangZhihui's Blog  

 

复制代码
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 

func FuncForPC(pc uintptr) *Func

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.

posted on   ZhangZhihuiAAA  阅读(7)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)
· winform 绘制太阳,地球,月球 运作规律
 
点击右上角即可分享
微信分享提示