ホームページ >バックエンド開発 >Golang >変更された変数を使用して Go で「defer」を正しく使用する方法は?

変更された変数を使用して Go で「defer」を正しく使用する方法は?

Mary-Kate Olsen
Mary-Kate Olsenオリジナル
2024-12-11 09:54:14412ブラウズ

How to Correctly Use `defer` in Go with Modified Variables?

defer 使用法の明確化

Go では、「defer」ステートメントを使用して、周囲の関数が戻る直前に関数が実行されるようにスケジュールできます。ただし、これは、囲んでいる関数内で変更される変数を扱うときに混乱を招く可能性があります。

元の問題

次の関数を考えてみましょう:

func printNumbers() {
  var x int

  defer fmt.Println(x)

  for i := 0; i < 5; i++ {
    x++
  }
}

Go 仕様では、「defer」ステートメントが実行されると、関数の値とパラメーターが評価され、後の実行のために保存されます。これは、関数が最終的に呼び出されるとき、延期時に評価されたため、x の値は 0 のままであることを意味します。

匿名関数による解決策

この問題を解決するには、次のようにします。 「defer」ステートメント内で匿名関数を使用できます:

defer func() { fmt.Println(x) }()

ここで、x は匿名関数のパラメータではないため、 「defer」ステートメントが実行されます。代わりに、匿名関数の呼び出し時に x の値がキャプチャされ、最新の値が確実に出力されます。

代替ソリューション

  1. ポインターの使用:

    var x int
    
    defer func() { fmt.Println(&x) }()

    このアプローチでは、x へのポインターを使用します。遅延関数のパラメータとして。 「defer」ステートメントが実行されると、x の値ではなくポインターのみが評価されます。遅延関数が呼び出されると、ポインターを介して x の現在値にアクセスします。

  2. カスタム タイプの使用:

    type MyInt int
    
    func (m *MyInt) String() string {
      return strconv.Itoa(int(*m))
    }
    
    var x MyInt
    
    defer fmt.Println(&x)

    この解決策はポインターのアプローチに似ていますが、String() メソッドを実装するカスタム型 (MyInt) を使用します。 String() を実装することで、x の値をどのように出力するかを制御できます。

  3. スライスの使用:

    var x []int
    
    defer fmt.Println(x)

    スライスとはGo の記述子の型。これは、その値が基になる配列への参照であることを意味します。スライスを延期すると、実際の配列要素ではなく参照のみが評価されます。その結果、延期後にスライス要素に加えられた変更は、印刷出力に反映されます。

  4. Struct でのラップ:

    type Wrapper struct {
      Value int
    }
    
    var x Wrapper
    
    defer fmt.Println(&x)

    このアプローチはポインターの使用に似ていますが、構造体内でポインターを逆参照する必要がないように、値を構造体でラップします。遅延関数。

以上が変更された変数を使用して Go で「defer」を正しく使用する方法は?の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。