1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

http.HandlerFunc は、型の名前 !!

Posted at

何かと分かりにくかった http.HandlerFunc について、まとめました。

まとめ

  • http.HandlerFunc は型の名前
  • http.HandlerFunc(関数) とすることで、関数を http.Handler インターフェースを満たした型として扱える
  • その関数は、func(http.ResponseWirter, *http.Request) という形 (シグネチャ) でないといけない

Go 言語の基本をおさらい

下記のように、独自の int 型を作れるように、あるシグネチャを持った関数も独自の型として定義できます。

type MyInt int
type MyFunc func(int, string) string

そうなんです。関数も型にできるんです。

そして、T(x) (参考: Go言語の仕様) とすることで、型変換ができます。
(T は変換したい型、x は変換する型)

func Index(i int, s string) string {
	return fmt.Sprintf("Int: %d, String: %s", i, s)
}

testInt := MyInt(1)
testMyFunc := MyFunc(Index)

fmt.Printf("The value is: %v\n", testInt) // The value is: 1
fmt.Printf("The value is: %v\n", testMyFunc(3, "hello")) // The value is: Int: 3, String: hello

どんな型になっているか念のため確認

fmt.Printf("%T\n", testInt)     // main.MyInt
fmt.Printf("%T\n", testMyFunc)  // main.MyFunc

関数を独自に作った型にでき、関数としても使えることが確認できました。

http.HandlerFunc を見てみる

Go のドキュメント: HandlerFunc から

type HandlerFunc func(http.ResponseWriter, *http.Request)

となっている。ふむふむ。

ということで、HanlderFunc は、型である ことが分かります。

また、HandlerFunc は、func (f HandlerFunc) ServeHTTP(w ResponseWriter, r *Request) のメソッドを持っているので (Go のドキュメント: type Handler)、http.Handler インターフェースを満たしています。

なので、func(http.ResponseWriter, *http.Request) という形(シグネチャ)の関数は、http.HandlerFunc(関数) とすることで、http.Handler 型として扱えるようになるということです。

では、どう使うのか?

middleware として使うことができ、ある処理の前に別の処理を実行させることができます。

下のコードは、画面に hello world と表示する前に、log.Println を実行する例

package main

import (
	"fmt"
	"log"
	"net/http"
)

func Index(w http.ResponseWriter, r *http.Request) {
	fmt.Fprintf(w, "Hello world")
}

func Log(h http.HandlerFunc) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		log.Println("Log is called")
		h(w, r)
	}
}

func main() {
	http.Handle("/", Log(Index))
	http.ListenAndServe(":8080", nil)
}
  • Log 関数は、http.HandlerFunc型を受け取り、http.HandlerFunc 型を返す関数
  • Index 関数 は、http.HandlerFunc 型になるための形(シグネチャ)になっている
  • なので、Log 関数は、Index 関数を受け取り、独自の処理(log.Prinln) のあと、そのまま受け取った関数 (= Index 関数) を実行する

http.HandleFunc は内部で http.HandlerFunc を実行している

http.HandleFunc("/", 関数A) とすることで、トップページへのリクエストがあった際に "関数A" を実行しますが、内部の実装をみると HandlerFunc が実行されています。

func (mux *ServeMux) HandleFunc(pattern string, handler func(ResponseWriter, *Request)) {
	if handler == nil {
		panic("http: nil handler")
	}
	mux.Handle(pattern, HandlerFunc(handler))

あー、すっきりした。

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?