【Go】Handle?Handler?HandlerFunc?HandleFunc?ややこしいのでまとめてみた
これは何
Goのhttpパッケージについて勉強していたときのこと。
「Handle、Handler、HandlerFunc、HandleFuncって名前ややこしすぎん?何が違うの?」 と思ったのでそれぞれの違いをまとめたものです。
この記事のゴール
- Handle、Handler、HandlerFunc、HandleFuncの違いを理解する。
結論
- HandleFuncはパスと
func(ResponseWriter, *Request)
を関連づけている。 - Handlerは
HTTPServe(ResponseWriter, *Request)
を持つインターフェース。 - HandlerFuncは
func(ResponseWriter, *Request)
を表す型でHandlerを実装している。 - Handleはパスと
Handlerインターフェース
を関連づけている。
HandleFunc
httpパッケージに実装されているHandleFunc関数を見てみます。
第一引数にパス、第二引数にfunc(w http.ResponseWriter, r *http.Request)
のシグネチャを持つ関数を受け取ります。
func HandleFunc(pattern string, handler func(ResponseWriter, *Request)) {
DefaultServeMux.HandleFunc(pattern, handler)
}
パスのパターンとハンドラを受け取ってマルチプレクサ
に登録します。
これによりパスとハンドラが関連づけられています。
実際の使い方
HandleFunc
は以下のように使うことができます。
http.HandleFunc("/HandleFunc", func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "handle func")
})
また、シグネチャが同じであれば関数を渡すことも可能です。
func hoge(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "handle func")
}
func main() {
http.HandleFunc("/HandleFunc, hoge)
}
HandlerFunc
HandleFuncに似た名前のものにHandlerFunc
があります。
これの実装を見てみます。
type HandlerFunc func(ResponseWriter, *Request)
// ServeHTTP calls f(w, r).
func (f HandlerFunc) ServeHTTP(w ResponseWriter, r *Request) {
f(w, r)
}
HandleFuncは関数だったのに対し、HandlerFunc
は型です。
よく考えてみれば、Handleという動詞とHandlerという名詞なので品詞で区別するとわかりやすいかもしれません。
また、ServeHTTP
メソッドを実装しているので、Handlerインターフェース
(後述)を満たしています。
ServeHTTP
が実行されると自身の関数が実行されるようになっています。
Handler
次にHandler
ですが、これはServeHTTPメソッドを持つインターフェースです。
先ほどのHandlerFuncがこのインターフェースを満たしていました。
type Handler interface {
ServeHTTP(ResponseWriter, *Request)
}
Handle
最後にHandle
を見てみます。
httpパッケージにおいてHandleは以下のようになっています。
func Handle(pattern string, handler Handler) { DefaultServeMux.Handle(pattern, handler) }
Handleは第二引数にHandlerインターフェース
を取るようになっています。
実装の内容としてはマルチプレクサにパスとhandlerを渡し、双方を関連づけています。
やっていることはHandleFunc
と同じですね。
違いは、HandleがHandlerインターフェース
を使っているのに対し、HandleFuncはfunc(ResponseWriter, *Request)
を使っているという点です。
実際の使い方
Handle
を使った実装は以下のようになります。
第二引数をHandlerFunc型
でキャストして渡します。
func main() {
http.Handle("/Handle", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "handle")
}))
http.ListenAndServe(":8080", nil)
}
HandlerFuncはHandlerインターフェースを満たしているので、キャストすることによってHandleに渡すことができます。
最後に
少しでも参考になれば幸いです!
Discussion