ホームページ >バックエンド開発 >Golang >go defer(遅延機能)の紹介

go defer(遅延機能)の紹介

尚
転載
2019-11-30 14:03:382340ブラウズ

go defer(遅延機能)の紹介

Go 言語 の defer は、少なくとも今日の主流のプログラミング言語と比較すると、この言語の新しい機能とみなされます。

defer ステートメントは関数を呼び出します。この関数の実行は、周辺関数が戻るか、周辺関数が最後まで実行されるか、または対応する goroutine パニックが発生するまで延期されます。

defer が指定されるたびに、後続の関数値 (Go では、関数は参照型であり、第一級市民であり、変数に代入できます) と関数パラメーターが評価されますが、関数は (↑) まですぐには呼び出されません。 ) 上記の 3 つの状況が発生します。これが defer の内容全体であり、残りは defer のベスト プラクティスです。

関数はすぐには呼び出されません

最も単純なものから始めます:

func readFile(fileName string){
    f,err := os.Open(fileName)
    if err!=nil {
        return
    }
    defer f.Close()
    var content [1024]byte
    f.Read(content[:])
    fmt.Printf("%s",content)
}
func main() {
    readFile("test.data")
}

プログラムは test.data の最初の 1024 バイトを出力します。このようなオープン/クローズのペアリング操作は defer の慣用的な使用法であることに注意してください。この例は、上記の文の後半を説明しています。

「ただし、関数は呼び出されません。」

because if f.Close() after defer が遅延していない場合、ファイル記述子がすべて閉じられている場合、何も読み取られません。

関数の値と関数のパラメーターは評価されますが、関数はすぐには呼び出されません。

次の例では前半を説明します。これは a8093152e673feb7aba1828c43532094 から来ています。 、少し変更:

func trace(funcName string) func(){
    start := time.Now()
    fmt.Printf("function %s enter\n",funcName)
    return func(){
        log.Printf("function %s exit (elapsed %s)",funcName,time.Since(start))
    }
}
 
func foo(){
    defer trace("foo()")()
    time.Sleep(5*time.Second)
}
func main(){
    foo()
    foo()
}
/*
OUTPUT:
function foo() enter
function foo() exit (elapsed 5.0095471s)
function foo() enter
function foo() exit (elapsed 5.0005382s)
*/

なぜ foo 出力は enter になり、exit を出力するまで約 5 秒待機しますか? 前述したように、

defer の後の関数の値とパラメータは評価されますが、実際の関数 呼び出しは最後まで待つ必要があります。

ここでの関数値は、trace() によって返される匿名関数です。関数パラメータは、もちろん文字列リテラル値 "foo()" です。trace の評価("foo()") は出力関数 foo() に入り、実際の関数呼び出し trace("foo()")()、つまり出力関数 foo() exit(elapsed x.x) は実行が返されるまで延期されます。 (return が戻り値変数を更新する場合、更新後に defer 関数を実行する前に実行されます)。

その他

もう少し詳しく言うと、複数の defer ステートメントがある場合、最後の defer 関数の実行順序は defer の出現順序と逆になります。例:

func main() {
    func1 := func(){
        fmt.Println("func1() execution deferred")
    }
    func2 := func(){
        fmt.Println("func2() execution deferred")
    }
    defer func1()
    defer func2()
    fmt.Println("strat\nworking...")
}
/*
OUTPUT:
strat
working...
func2() execution deferred
func1() execution deferred
*/

以上がgo defer(遅延機能)の紹介の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事はcnblogs.comで複製されています。侵害がある場合は、admin@php.cn までご連絡ください。