ホームページ > バックエンド開発 > Golang > Go で `defer func() { fmt.Println(i) }()` が '44444' を出力するのに、 `defer func(n int) { fmt.Println(n) }(i)` は正しく '43210' を出力するのはなぜですか?

Go で `defer func() { fmt.Println(i) }()` が '44444' を出力するのに、 `defer func(n int) { fmt.Println(n) }(i)` は正しく '43210' を出力するのはなぜですか?

DDD
リリース: 2024-11-10 18:54:02
オリジナル
497 人が閲覧しました

Why does `defer func() { fmt.Println(i) }()` print

遅延関数呼び出しとクロージャ キャプチャ

Go では、defer ステートメントを使用すると、周囲の関数が戻る直前に関数を実行できます。 defer の重要な側面の 1 つは、クロージャの処理方法です。

このコード スニペットでは:

package main

import "fmt"

func main() {
    var whatever [5]struct{}

    for i := range whatever {
        fmt.Println(i)
    } // part 1

    for i := range whatever {
        defer func() { fmt.Println(i) }()  // part 2
    }

    for i := range whatever {
        defer func(n int) { fmt.Println(n) }(i)  // part 3
    }
}
ログイン後にコピー

パート 1 では、単純に i の値を 0 から 4 まで出力します。ただし、パート 2 では、次のことを示します。興味深い行動。 0 ~ 4 の期待値を出力する代わりに、「44444」を出力します。

これは、パート 2 のクロージャが i 変数をキャプチャしているためです。後でクロージャが実行されると、変数 i には、range ステートメントの最後の反復で持っていた値、つまり 4 が入ります。その結果、すべての遅延関数呼び出しでは 4 が出力されます。

対照的に、パート3 は外部変数をキャプチャしません。 Go の仕様によれば、「『defer』ステートメントが実行されるたびに、呼び出しに対する関数の値とパラメーターが通常どおり評価され、新たに保存されますが、実際の関数は呼び出されません。」これは、遅延関数呼び出しのそれぞれに異なる値の 'n' パラメーターがあることを意味します。これは、'defer' ステートメントが実行された時点の 'i' の値です。

したがって、パート 3 は正しくなります。遅延関数呼び出しは周囲の関数の前に LIFO 順序 (後入れ先出し) で実行されるため、「43210」が出力されます。

'defer f(e)' の式は即座に評価されるのに対し、'defer f()' の関数式は defer ステートメントの実行時には実行されないことを覚えておくことが重要です。

以上がGo で `defer func() { fmt.Println(i) }()` が '44444' を出力するのに、 `defer func(n int) { fmt.Println(n) }(i)` は正しく '43210' を出力するのはなぜですか?の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

ソース:php.cn
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート