目次
機能 3: defer 後の関数パラメータは宣言時に確認されます (事前計算されたパラメータ) " >機能 3: defer 後の関数パラメータは宣言時に確認されます (事前計算されたパラメータ)
github.com/newbugcoder/learngo/tre...
ホームページ バックエンド開発 Golang 8 つのデモを使用して Go 言語の defer の 5 つの主要な機能を理解する

8 つのデモを使用して Go 言語の defer の 5 つの主要な機能を理解する

Apr 23, 2023 pm 05:40 PM
言語を移動

Go 言語で defer キーワードを使用すると、関数の終了までコードの実行が遅れる可能性があります。開発では、開いているファイル記述子を閉じる、接続を閉じる、リソースを解放するなど、その後の作業を完了するために defer キーワードを使用することがよくあります。

func demo0() {
    fileName := "./test.txt"
    f, _ := os.OpenFile(fileName, os.O_RDONLY, 0)
    defer f.Close()

    contents, _ := ioutil.ReadAll(f)
    fmt.Println(string(contents))}
ログイン後にコピー

deferキーワードは通常、リソースを解放し忘れることを防ぐために、リソースを開くコードの直後に続きます。defer で宣言されたコードは、関数が終了するまで実際には実行されません。 defer はシンプルで使いやすいですが、 しかし、その機能を無視すると、開発中に混乱に直面することになります。そこで、defer の 5 つの主要な機能をまとめ、8 つのデモを通して defer の機能を段階的に紹介しました。

機能 1: 複数の defer が使用される場合の呼び出し順序: 先入れ、後出し

複数の defer キーワードが使用される場合、最初に宣言された defer ステートメントが後で呼び出されます。 「スタック」の

first-in-last-out 機能と同様に、この defer の機能も理解しやすいです。 最初に によって開かれたリソースは、後続のコードによって依存される可能性があるため、 の後に を放しても安全です。

func demo1() {
    for i := 0; i < 5; i++ {
        defer fmt.Println("defer:", i)
    }}// defer: 4// defer: 3// defer: 2// defer: 1// defer: 0
ログイン後にコピー
機能 2: スコープは現在の関数であり、さまざまな関数の下にさまざまな遅延スタックがあります

デモ 2 を実行します。結果から、最初の匿名関数と 2 番目の匿名関数が実行されていることがわかります。匿名関数 関数の遅延実行の順序は重要ではありません。

遅延スコープは現在の関数のみであり、現在の関数の最後に実行されるため、関数ごとに異なる遅延スタックが存在します。

func demo2() {
    func() {
        defer fmt.Println(1)
        defer fmt.Println(2)
    }()

    fmt.Println("=== 新生代农民工啊 ===")

    func() {
        defer fmt.Println("a")
        defer fmt.Println("b")
    }()}// 2// 1// === 新生代农民工啊 ===// b// a
ログイン後にコピー
demo3_1 を実行し、結果に従って次の結論を得ることができます: defer in

仮パラメータnの値は、実行時のではなく、宣言時に確定するため、後続の変数numがどのように変化しても出力結果には影響しません。延期の。

func demo3_1() {
    num := 0
    defer func(n int) {
        fmt.Println("defer:", n)
    }(num)
    // 等同 defer fmt.Println("defer:", num)

    for i := 0; i < 10; i++ {
        num++
    }

    fmt.Println(num)}//10//defer: 0
ログイン後にコピー
demo3_2 を実行します。ここでの defer の最終出力結果が変数 num と同じなのはなぜですか?ここではポインタが使用されているためです。

defer
を宣言すると、仮引数 p ポインタが指すアドレスが変数 num を指していることが確認され、変数 num が変化します。したがって、defer が実行されると、出力は p ポインタが指す変数 num の現在の値になります。

func demo3_2() {
    num := 0
    p := &num    defer func(p *int) {
        fmt.Println("defer:", *p)
    }(p)

    for i := 0; i < 10; i++ {
        num++
    }

    fmt.Println(*p)}//10//defer: 10
ログイン後にコピー
defer3_3 をもう一度見てください。defer によって出力された変数は、関数パラメータを介して渡されません。「グローバル変数」num は defer

が実行されたときにのみ取得されるため、defer の出力結果は次のようになります。変数と同じです。num は一貫しています。

func demo3_3() {
    num := 0
    defer func() {
        fmt.Println("defer:", num)
    }()

    for i := 0; i < 10; i++ {
        num++
    }

    fmt.Println(num)}//10//defer: 10
ログイン後にコピー
機能 4: return と defer の実行順序: return first defer thendefer と return は関数の最後に実行されますが、return が前に実行されることがわかります。 defer;

func demo4_1() (int, error) {
    defer fmt.Println("defer")
    return fmt.Println("return")}// return// defer
ログイン後にコピー

これは出力結果

からも明らかですが、returnとdeferの実行順序と

**関数の戻り値** 「会う」、多くの複雑なシナリオが発生します。 demo4_2 では、関数は を使用して戻り値 に名前を付け、最終的な出力結果は 7 です。

(1つ目) 変数 num を戻り値として使用し、初期値は 0;
  1. (2 回目) その後、変数 num には値 10 が割り当てられます;
  2. (その後) 戻ると、変数 num には戻り値として値 2 が再割り当てされます;
  3. (その後) return 後に defer が実行され、変数 num が取得されて変更され、値は 7;
  4. (最後に) 変数 num が戻り値として使用され、最終的な関数の戻り結果は 7;
  5. func demo4_2() (num int) {
     num = 10
     defer func() {
         num += 5
     }()
    
     return 2}// 7
    ログイン後にコピー
  6. 別の例を見てみましょう。
  7. demo4_3 では、関数は
匿名の戻り値

を使用し、最終的な結果出力は 2 です。プロセスは次のとおりです:

関数に入りますが、この時点では戻り値の変数は作成されません;
  1. は変数 num を作成します値を 10 に割り当てます。
  2. return のとき、関数の戻り値変数を作成し、値 2 を割り当てます。この戻り値変数は匿名変数、または次のように考えることができます。 a、b、c、または d 変数 ... ですが、それは変数 num ではありません。
  3. defer、変数 num をどのように変更しても、それは変数 num とは何の関係もありません。関数の戻り値;
  4. したがって、最終的な関数の戻り結果は 2 になります;
  5. func demo4_3() int {
     num := 10
     defer func() {
         num += 5
     }()
    
     return 2}// 2
    ログイン後にコピー
  6. 特徴 5: パニックが発生すると、宣言された defer がスタックから飛び出します

    デモ5_1 を実行すると、パニックが発生すると、宣言された defer がトリガーされてスタックから飛び出し、パニックになることがわかりますが、パニック後に宣言された defer は実行されません。

    func demo5_1() {
     defer fmt.Println(1)
     defer fmt.Println(2)
     defer fmt.Println(3)
    
     panic("没点赞异常") // 触发defer出栈执行
    
     defer fmt.Println(4) // 得不到执行}
    ログイン後にコピー

    この機能を使用することで、遅延時の回復を通じてパニックを捕捉し、プログラムのクラッシュを防ぐことができます。

    func demo5_2() {
     defer func() {
         if err := recover(); err != nil {
             fmt.Println(err, "问题不大")
         }
     }()
    
     panic("没点赞异常") // 触发defer出栈执行
    
     // ...}
    ログイン後にコピー
    添付

    完全なコード:

    github.com/newbugcoder/learngo/tre...

以上が8 つのデモを使用して Go 言語の defer の 5 つの主要な機能を理解するの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

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

ホットな記事タグ

メモ帳++7.3.1

メモ帳++7.3.1

使いやすく無料のコードエディター

SublimeText3 中国語版

SublimeText3 中国語版

中国語版、とても使いやすい

ゼンドスタジオ 13.0.1

ゼンドスタジオ 13.0.1

強力な PHP 統合開発環境

ドリームウィーバー CS6

ドリームウィーバー CS6

ビジュアル Web 開発ツール

SublimeText3 Mac版

SublimeText3 Mac版

神レベルのコード編集ソフト(SublimeText3)

golang でリフレクションを使用してプライベート フィールドとメソッドにアクセスする方法 golang でリフレクションを使用してプライベート フィールドとメソッドにアクセスする方法 May 03, 2024 pm 12:15 PM

golang でリフレクションを使用してプライベート フィールドとメソッドにアクセスする方法

golang 関数で新しい関数を動的に作成するためのヒント golang 関数で新しい関数を動的に作成するためのヒント Apr 25, 2024 pm 02:39 PM

golang 関数で新しい関数を動的に作成するためのヒント

Go 言語でのパフォーマンス テストと単体テストの違い Go 言語でのパフォーマンス テストと単体テストの違い May 08, 2024 pm 03:09 PM

Go 言語でのパフォーマンス テストと単体テストの違い

Golang テクノロジーを使用して分散システムを設計する場合、どのような落とし穴に注意する必要がありますか? Golang テクノロジーを使用して分散システムを設計する場合、どのような落とし穴に注意する必要がありますか? May 07, 2024 pm 12:39 PM

Golang テクノロジーを使用して分散システムを設計する場合、どのような落とし穴に注意する必要がありますか?

機械学習で使用される Golang テクノロジー ライブラリとツール 機械学習で使用される Golang テクノロジー ライブラリとツール May 08, 2024 pm 09:42 PM

機械学習で使用される Golang テクノロジー ライブラリとツール

golang 関数の命名規則の進化 golang 関数の命名規則の進化 May 01, 2024 pm 03:24 PM

golang 関数の命名規則の進化

モバイルIoT開発におけるGolangテクノロジーの役割 モバイルIoT開発におけるGolangテクノロジーの役割 May 09, 2024 pm 03:51 PM

モバイルIoT開発におけるGolangテクノロジーの役割

golang 変数パラメータは関数の戻り値に使用できますか? golang 変数パラメータは関数の戻り値に使用できますか? Apr 29, 2024 am 11:33 AM

golang 変数パラメータは関数の戻り値に使用できますか?

See all articles