初めに
参考になる記事がたくさんあるので、まずリンクを貼る
目的
自分はあまり理解力が高くないので、記事を見るだけでは理解できなかったりする。
参考になる記事たちを見て、改めて自分の中で整理してこの記事でアウトプットすることで自分の理解を深める
下記サンプルコードをもとに理解を深める
package main
import (
"net/http"
"github.com/koga456/sample-api/controller"
"github.com/koga456/sample-api/model/repository"
)
var tr = repository.NewTodoRepository()
var tc = controller.NewTodoController(tr)
var ro = controller.NewRouter(tc)
func main() {
server := http.Server{
Addr: ":8080",
}
http.HandleFunc("/todos/", ro.HandleTodosRequest)
server.ListenAndServe()
}
コードリーディング
server := http.Server{
Addr: ":8080",
}
server変数にhttpパッケージのServer型にAddrのみ指定して代入
http.HandleFunc("/todos/", ro.HandleTodosRequest)
func HandleFunc(pattern string, handler func(ResponseWriter, *Request)) {
DefaultServeMux.HandleFunc(pattern, handler)
}
pattern(パス)とfunc(ResponseWriter, *Request)型のhandlerを引数にDefaultServeMuxのHandleFuncメソッドを実行している
// DefaultServeMux is the default ServeMux used by Serve.
var DefaultServeMux = &defaultServeMux
var defaultServeMux ServeMux
DeualtServeMuxはServeMux型の変数。
要するにhttp.HandleFuncはServeMux型をレシーバにもつHandleFuncメソッドを実行している。
// HandleFunc registers the handler function for the given pattern
func (mux *ServeMux) HandleFunc(pattern string, handler func(ResponseWriter, *Request))
HandleFunc(httpパッケージのServeMux型をレシーバにもつHandleFuncメソッド)
ServeMux型をレシーバに持つメソッドであり、pattern(/todos/)にhandler関数を登録(httpパッケージのServeMux型をレシーバに持つHandleメソッドを呼び出し)する
serveMux型,muxEntry型
type ServeMux struct {
mu sync.RWMutex
m map[string]muxEntry
es []muxEntry // slice of entries sorted from longest to shortest.
hosts bool // whether any patterns contain hostnames
}
type muxEntry struct {
h Handler
pattern string
}
http.ServeMux.Handleは何をするのか
ソースコード
// Handle registers the handler for the given pattern.
// If a handler already exists for pattern, Handle panics.
func (mux *ServeMux) Handle(pattern string, handler Handler) {
mux.mu.Lock()
defer mux.mu.Unlock()
if pattern == "" {
panic("http: invalid pattern")
}
if handler == nil {
panic("http: nil handler")
}
if _, exist := mux.m[pattern]; exist {
panic("http: multiple registrations for " + pattern)
}
if mux.m == nil {
mux.m = make(map[string]muxEntry)
}
e := muxEntry{h: handler, pattern: pattern}
mux.m[pattern] = e
if pattern[len(pattern)-1] == '/' {
mux.es = appendSorted(mux.es, e)
}
if pattern[0] != '/' {
mux.hosts = true
}
}
pattern(パス)に対応づけてmux[string]muxEntryとして登録している
mux.Handle(pattern, HandlerFunc(handler))
handler(func ResponseWriter, *Request)をHandlerFunc型に変換してから渡すことで
func (m *ServeMux) Handle(pattern string, handler Handler)のHandler型に納めている
HandlerFunc型,Handler型
type HandlerFunc func(ResponseWriter, *Request)
func (f HandlerFunc) ServeHTTP(w ResponseWriter, r *Request)
type Handler interface {
ServeHTTP(ResponseWriter, *Request)
}
HandlerFunc型はServeHttpメソッドを実装していて、 Handlerはインターフェースであり、ServeHttpを実装していることが求められていることがわかる
上記HandlerFunc型に変換しているのはServeHttpを実装させるため、実装していればHandler Interfaceに収まる。
server.ListenAndServe()
先ほど定義したserver変数のListenAndServeメソッドを実行している。
// ListenAndServe listens on the TCP network address srv.Addr and then calls Serve to handle requests on incoming connections.
// Accepted connections are configured to enable TCP keep-alives.
func (srv *Server) ListenAndServe() error
server型 他にもたくさんあるけど、よく使う?ものだけ抜粋
type Server struct {
// Addr optionally specifies the TCP address for the server to listen on,
// in the form "host:port". If empty, ":http" (port 80) is used.
// The service names are defined in RFC 6335 and assigned by IANA.
// See net.Dial for details of the address format.
Addr string
Handler Handler // handler to invoke, http.DefaultServeMux if nil
}
今回、server型のAddrのみ指定して、Handlerは指定しなかったため、http.DefaultServeMuxになる
DefaultServeMuxについては上に書いたとおり、HandleFuncが呼び出されていく
まとめ • 感想
今回色々な記事を見て頭に入らなかった原因がこの記事を書いている内にわかった
- 公式のdocを全然見てなかった
下記に理由はあるが、公式のドキュメントを読んでいなかった
- メソッドについての理解が足りていなかった
A Tour of Goをさらっと流し読みして、分かった気になっていたが、メソッド関数と関数の違いを分かっていなかったのでドキュメントを見てもイマイチピンと来なかった
後は書いている内に理解が深まっていった(わかっていないところがわかるようになった)ので、いい記事を書こうとは思わず、誰が見るわけでもないと思って気軽に書いていきたい