36

これが私のコードです(run):

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
}

出力:

0 1 2 3 4 4 3 2 1 0 4 4 4 4 4

質問: パート 2 とパート 3 の違いは何ですか? パート 2 で「43210」ではなく「44444」が出力されるのはなぜですか?

4

2 に答える 2

45

「パート 2」のクロージャは、変数「i」をキャプチャします。クロージャーのコードが (後で) 実行されると、変数 'i' は範囲ステートメントの最後の反復での値を持ちます。「4」。従って

4 4 4 4 4

出力の一部。

「パート 3」は、そのクロージャで外部変数をキャプチャしません。仕様が言うように:

「defer」ステートメントが実行されるたびに、呼び出しに対する関数値とパラメーターが通常どおり評価され、新たに保存されますが、実際の関数は呼び出されません。

そのため、延期された関数呼び出しごとに、「n」パラメーターの値が異なります。これは、defer ステートメントが実行された瞬間の 'i' 変数の値です。従って

4 3 2 1 0

出力の一部:

... 遅延呼び出しは、周囲の関数が戻る直前に LIFO の順序で実行されます ...


注意すべき重要な点は、「defer f()」内の「f()」は、defer ステートメントの実行時に実行されないことです。

しかし

'defer f(e)' の式 'e'は、defer ステートメントの実行時に評価されます。

于 2013-04-15T08:32:15.763 に答える