Skip to content

函数字面量和闭包

函数字面量就是匿名函数。

闭包与函数最大的区别就是它不用再手动将参数在函数之间传来传去,而是会自动捕获闭包体所需要的环境。

go
// 为每个处理器添加一个字符串参数
func viewHandler(w http.ResponseWriter, r *http.Request, title string)
func editHandler(w http.ResponseWriter, r *http.Request, title string)
func saveHandler(w http.ResponseWriter, r *http.Request, title string)

// 删去每个处理器里原本获取title的代码
// 略

// 添加一个包装函数,参数是原本的处理器函数。
// 包装函数将原处理器与新代码包装成一个匿名函数(闭包)。
// 参数 w http.ResponseWriter, r *http.Request 并不会经过 makeHandler 之手,而是给匿名函数加上同样的参数,并将匿名函数直接转交给上一级 http.HandleFunc()。
// 所以,这就是 makeHandler() 的参数并不符合调用,但仍然能使用的原因。它像一个隐形的中间人,给处理步骤加点料,但两边都不察觉,这就是 middleware(中间件)的最简原型。
func makeHandler(fn func(http.ResponseWriter, *http.Request, string)) http.HandlerFunc {
    return func(w http.ResponseWriter, r *http.Request) {
        // 将 getTitle 函数的代码移进闭包中
        m := validPath.FindStringSubmatch(r.URL.Path)
        if m == nil {
            http.NotFound(w, r)
            return
        }
        // 将title传入并执行原处理器函数
        fn(w, r, m[2])
    }
}

// 将包装函数注册为处理器,替换老的代码
func main() {
    http.HandleFunc("/view/", makeHandler(viewHandler))
    http.HandleFunc("/edit/", makeHandler(editHandler))
    http.HandleFunc("/save/", makeHandler(saveHandler))

    log.Fatal(http.ListenAndServe(":8080", nil))
}