衝突コース第VII部:機能,閉鎖および延期



関数
前の章では、いくつかの機能について話しました.しかし、これらの機能のいくつかのより多くの機能をカバーすることができます.関数はGO構文の最初のクラスの市民です.これは、関数が他の型のようで、他の関数に渡され、関数から返されることを意味します.しかし、もう一つの関数は、関数型を定義することです.
type HandlerFunc func(ResponseWriter, *Request)

The above is from actual source code of go pkg net/http HandlerFunc


関数の型定義を作成できることは素晴らしいです.我々がこれをしたい主な理由のうちの1つは、私たちにより少ないコードを書かせます.
func takesFunc(func (int, string, bool) (bool, error)) int

//vs

type CrazyFunc(int, string, bool) (bool, error)
func takesFunc(c CrazyFunc) int
つの間に、私は後で後で読みやすくて、一目でわかることを議論します.誰もが簡単にどのような契約を知ることができるコードベースにジャンプtakesFunc 達成する必要性また、CrazyFunc 引数として、我々はより少ないコードを書くことに終わります.その勝利.
しかし、関数型を定義することができるより重要な利点は、メソッドを関数にアタッチできることです.私たちはまだメソッドについて話しませんでした(私たちが構造について話すとき、メソッドについてより多くを学びます)、短い方法では特定のタイプに付けられる機能です.このメソッドは、func キーワードと関数名.メソッドを定義することができるのは本当に機能的なインターフェースを実装できるからです.例のようにHandlerFunc 関数.方法を取り付けるServeHTTP これは関数自体と現在の私たちの呼び出しHandlerFunc 実装Handler 建物に必要なインターフェースhttp サーバ.
func (f HandlerFunc) ServeHTTP(w ResponseWriter, r *Request) {
    f(w, r)
}
今私たちのコードでは、我々はHandle メソッド*http.ServeMux 我々は、任意の機能を同じ署名で送信することができますHandlerFunc キャスティングHandlerFunc .

In practice we probably will use the HandleFunc method that does the casting for us. But its possible.


あなたが我々がここで話したすべてを理解しないならば、心配しないでください.これはあなたに可能なことを迅速に垣間見ることを意味します.これらすべてを適切に利用することができる基本的な知識が必要です.

閉鎖
クロージャを理解する前に、匿名関数を理解する必要があります.

匿名関数
名前が示す匿名関数は匿名です.名前を持たない関数です.Goでは、変数として、あるいは戻り値としてインライン関数を定義できます.
adder := func(a int, b int) int {
    return a + b
}

閉鎖
クロージャは関数スコープの外部で定義された変数を参照する匿名関数です.関数のスコープは有効です.
func counter() func() int {
    i := 0
    return func() int {
        i++
        return i
    }
}
この例では、関数がありますcounter この関数は、counter . それで、我々が返す内部の機能は閉鎖です.
我々のコードでは、この関数を使用することができます
counter1 := counter()
counter2 := counter()

fmt.Println(counter1()) // 1
fmt.Println(counter2()) // 1
我々は、彼らが呼ばれるたびに成長する2つの独立したカウンタを作成している.カウンターはおそらく閉鎖のためのかなり滑稽な例です、しかし、私はそれが向こう側に得ることを望みます.があるthis amazing article by Jon Calhoun それは、クロージャが我々のコードを改善するために利用できるより多くの深さに入ります.

延期する
go - deferキーワードは、周囲の関数が戻るまで、関数の実行を延期するために使用されます.
func deferredPrint() {
    defer fmt.Println("defer 1")
    fmt.Println("regular thing")
    defer fmt.Println("defer 2")
}
実行deferredPrint ウィルプリント
regular thing
defer 2
defer 1
ここで2つの重要な観測があります.第一にfmt.Println 最初に実行されたdeferなしの関数呼び出し.DEFERが関数の最後に到達するまで、他の関数呼び出しの実行を延期するので、これは意味があります.第二に、我々のdefer関数からの印刷は逆の順序であるようです.これはランダムではありません.我々が持っているすべての延期は、逆の順序で実行します.
deferは特に何が起こっても何らかのアクションを取りたいとき、DB接続を閉じたりファイルを閉じたりするときに便利です.延期はパニック回復にも便利です.我々はパニックについてまだ話していない.通常、私たちのプログラムでパニックに良いアイデアはないが、場合には、その適切な場合があります.後の章ではパニックについてお話します.

次の手順
これは、このGOクラッシュコースシリーズの第7部です.