前言
之前在看 http.HandlerFunc 相关的代码时,对 Handler,HandlerFunc,HandleFunc 的联系困在细节中。本篇文章就是来理清相关联系和 Go 在此上的设计。
正文
接口型函数,在 java 里面就是类似 lambda 的语法糖。
// 1.8+ 写法
Collections.sort(list, (Integer o1, Integer o2) -> o2 - o1 );
// 1.8 之前的写法
Collections.sort(list, new Comparator<Integer>(){
@Override
public int compare(Integer o1, Integer o2) {
return o2 - o1;
}
});
从构造一个匿名对象简化为之需要一个 lambda 表达式,从面向对象转化为函数式编程。
同样的,Go 里面的接口型函数也是只定义了一个方法的接口类型。下面先来看看 net/http 中的使用:
net/http
先把 Handler,HandlerFunc,HandleFunc 这几个全部列出来:
// Handler 定义
type Handler interface {
ServeHTTP(ResponseWriter, *Request)
}
// HandlerFunc 定义 L2008
type HandlerFunc func(ResponseWriter, *Request)
func (f HandlerFunc) ServeHTTP(w ResponseWriter, r *Request) {
f(w, r)
}
// Handle 定义
func Handle(pattern string, handler Handler)
HandleFunc
// HandleFunc 定义 L2436
func (mux *ServeMux) HandleFunc(pattern string, handler func(ResponseWriter, *Request)) {
if handler == nil {
panic("http: nil handler")
}
mux.Handle(pattern, HandlerFunc(handler))
}
可以看的出来 HandleFunc 的 handler 是一个明确的函数签名不是别名,所以如果你使用 HandleFunc,一般这么使用:
// 明确的函数签名
func home(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
_, _ = w.Write([]byte("hello, index page"))
}
func main() {
http.HandleFunc("/home", home)
_ = http.ListenAndServe("localhost:8000", nil)
}
HandlerFunc
先看怎么用:
func home(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
_, _ = w.Write([]byte("hello, index page"))
}
func main() {
// 这句话就是将 /home -> home 进行路由绑定
http.Handle("/home", http.HandlerFunc(home))
// 再启动 Server
_ = http.ListenAndServe("localhost:8000", nil)
}
可以看到 http.HandlerFunc(home) ,是把明确的函数签名通过类型转换强转为 HandlerFunc,为什么这么做呢?
来看看 Handle 这个处理函数:
// 直接交给 http 中的默认路由进行路由绑定处理
func Handle(pattern string, handler Handler) {
DefaultServeMux.Handle(pattern, handler)
}
传入的是一个 Handler ,这是一个接口。而 HandlerFunc 实现了 Handler ,并且它是一个函数类型。路由处理函数通过类型转换,将 home 转换为 HandlerFunc,也间接实现了 Handler。
所以这就是为什么你不需要显式实现 Handler 的 Get() ,你的函数就可以和路由绑定的原因。