net/http
のHandler周りのコードを読んでいたらよくわからなくなったので理解のため簡単なコードを書いておきます。
HTTPserver
package main import ( "fmt" "net/http" ) func main() { // HandlerFunc は与えられたパターン(/hello) をDefaultServeMuxに登録します http.HandleFunc("/hello", helloHandler) http.ListenAndServe(":8080", nil) } func helloHandler(w http.ResponseWriter, r *http.Request) { fmt.Println("Hello") }
これは/hello
にアクセスが来るとHelloと出力するHTTPサーバです。よくサンプルなどでみる簡単なものですが、裏側がどうなっているのかをあまり気にしたことはありませんでした。
こちらの記事でまとめてくれていますが、
func helloHandler(w http.ResponseWriter, r *http.Request) { fmt.Println("Hello") }
この定義した関数をHandleFuncに渡して登録してもらうと、起動するサーバにて/hello
のリクエスト時にhelloHandler関数を実行してくれます。
http.HandleFunc("/hello", helloHandler)
で、よく分からなかったのが関数名を渡しているところです。これをどうやって処理しているんだろう?ときになり、簡単なサンプルコードを書いてみました。
サンプル
package main import "fmt" type TestFunc func(int, int) int type ValuePool struct { a int b int } func sum(a int, b int) int { return a + b } func diff(a int, b int) int { return a - b } func (t ValuePool) Run(f TestFunc) { fmt.Println(f(t.a, t.b)) } func main() { a, b := 100, 100 v := &ValuePool{a, b} v.Run(sum) v.Run(diff) }
このコードは以下で動かせます。
これが何をやっているのかを簡単に紹介します。ここが実際の処理を読んでいる箇所なのですが、sum
とdiff
関数をそれぞれよんでいます。関数自体は四則演算なので内容は割愛しますが関数名を変えるだけで結果を変えることができています。
v.Run(sum) v.Run(diff)
これをどのように実現しているのかというとTestFunc
が肝になります。この型はfunc(int, int) int
を表しています(別名)。同様にsumやdiff関数も同じ引数と戻り値の構造になっていますね。
type TestFunc func(int, int) int 〜 func sum(a int, b int) int { return a + b } func diff(a int, b int) int { return a - b }
つまりsumやdiff関数はTestFuncと同じである(型的に)と見なすことができるのです。そのためこんなこともできちゃいます。
var t TestFunc t = sum fmt.Println(t(a, b)) t = diff fmt.Println(t(a, b))
さて、このように関数をキャストすることができるので次はこのメソッドを見ます。これはValuePool構造体のメソッドでTestFunc型を引数にとって、受け取った関数を実行します。
func (t ValuePool) Run(f TestFunc) { fmt.Println(f(t.a, t.b)) }
そのため先ほど紹介したsumやdiff関数をここで実行しているのです。このようにすることでHTTPのところであった以下の関数も、引数が(w http.ResponseWriter, r *http.Request)
で戻り値の無いfunc(w http.ResponseWriter, r *http.Request)
型にキャストされ処理が行われるということですね。
func helloHandler(w http.ResponseWriter, r *http.Request) { fmt.Println("Hello") }
自分で書いてみるとなんとなくわかりますが、これを使ってコードをシンプルにしよう!ってなるとまだまだヒラメかなさそうですね。。