Go 接口型函数的应用 | 八日打卡

454 阅读2分钟

前言

之前在看 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

先把 HandlerHandlerFuncHandleFunc 这几个全部列出来:

// 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))
}

可以看的出来 HandleFunchandler 是一个明确的函数签名不是别名,所以如果你使用 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

所以这就是为什么你不需要显式实现 HandlerGet() ,你的函数就可以和路由绑定的原因。