函数作为返回值的使用场景

一、函数包装

现在有一个简单的 HTTP 服务器,监听并接受来自客户端的请求。

1
2
3
4
5
6
7
8
9
func main() {
    server := http.Server{Addr: "127.0.0.1:8080"}
    http.HandleFunc("/hello", hello)
    server.ListenAndServe()
}

func hello(w http.ResponseWriter, r *http.Request) {
    fmt.Fprintf(w, "hello world")
}

我们现在需要监控 hello 函数处理请求的用时,应该如何操作呢?

我们很容易就能想到在hello函数中添加一个计时器,然后打印出函数执行的时间。

但这样需要我们直接修改hello函数的内容,有没有一种非入侵式的办法呢?

我们可以在原函数外面再包装一层函数,在新函数中去实现计时的逻辑,需要用到 函数作为参数函数作为返回值。代码如下:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
func main() {
    server := http.Server{Addr: "127.0.0.1:8080"}
    http.HandleFunc("/hello", timed(hello))
    server.ListenAndServe()
}

func hello(w http.ResponseWriter, r *http.Request) {
    fmt.Fprintf(w, "hello world")
}

func timed(f func(w http.ResponseWriter, r *http.Request)) func(w http.ResponseWriter, r *http.Request) {
    return func(w http.ResponseWriter, r *http.Request) {
       start := time.Now()
       f(w, r)
       end := time.Now()
       fmt.Println("请求耗时:", end.Sub(start))
    }
}

这样,每发送一次HTTP请求,就会调用一次timed函数,输出请求耗时。

这种方式称为函数包装(Function Wrapping)或函数装饰(Function Decoration),通过包装函数,可以在不修改原始函数的情况下增加额外的功能,比如计时、日志记录等。

0%