Defer 使用法の明確化: 最終的な変数値の出力
Go では、defer キーワードを使用して、関数が実行される直前に実行されるようにスケジュールできます。周囲の関数が戻ります。ただし、遅延関数が周囲の関数内で変更される可能性のあるローカル変数を使用する場合は、正しい値が使用されるように特別な注意を払う必要があります。
次の関数を考えてみましょう:
func printNumbers() { var x int defer fmt.Println(x) for i := 0; i < 5; i++ { x++ } }
言語仕様に従って、defer ステートメントが実行されると、ローカル変数が評価され、新たに保存されます。ただし、実際の関数は後になるまで呼び出されません。この場合、defer ステートメントが実行されるとき、x の値は 0 であるため、deferred 関数が呼び出されたときに 0 が出力されます。
この問題を解決するには、いくつかの方法のいずれかを使用できます。
1.匿名関数の場合:
defer func() { fmt.Println(x) }()
これは、x の現在値をキャプチャする匿名関数を使用します。匿名関数が呼び出されると、周囲の関数で x が変更された場合でも、キャプチャされた値が使用されます。
2.ポインタの場合:
var x int defer Print(&x)
x へのポインタを使用し、ポイントされた値を出力する関数を延期できます。ポインタ値は defer ステートメントの実行時に評価されますが、指定された値は deferred 関数が呼び出されるまで評価されないため、これが機能します。
3.カスタム タイプの場合:
type MyInt int func (m *MyInt) String() string { return strconv.Itoa(int(*m)) } var x MyInt defer fmt.Println(&x)
ここでは、fmt.Stringer インターフェイスを実装するカスタム タイプ MyInt を作成し、値の出力方法を指定できるようにします。 &x が出力されると、String メソッドが呼び出され、ポイントされた値の文字列表現が返されます。
4.ラッピング:
x := []int{0} defer fmt.Println(x)
変数をスライスでラップすると、スライスの内容を出力する関数を延期できます。スライス記述子は defer ステートメントの実行時に評価されますが、基礎となる配列は deferred 関数が呼び出されるまで評価されません。
defer 関数で使用されている変数は、次のパラメータであってはいけないことを覚えておくことが重要です。 defer ステートメントの実行時にパラメーターが評価されるため、遅延関数自体。
以上がローカル変数の変更に対処するときに Go で Defer を正しく使用するにはどうすればよいですか?の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。