ホームページ > バックエンド開発 > Golang > Go でリソースを適切に解放するには、ループ内のどこに「defer」ステートメントを配置すればよいですか?

Go でリソースを適切に解放するには、ループ内のどこに「defer」ステートメントを配置すればよいですか?

Susan Sarandon
リリース: 2025-01-02 17:21:40
オリジナル
636 人が閲覧しました

Where Should I Place `defer` Statements in a Loop to Properly Release Resources in Go?

ループ内で遅延を使用してリソースを解放する方法: 最良のアプローチ

ループ内でデータベース クエリが関与するコンテキストでは、次のような疑問が生じます。 defer ステートメントを最適に配置して、適切なリソース解放を確保します。次のループを考えてみましょう:

for rows.Next() {

   fields, err := db.Query(.....)
   if err != nil {
      // ...
   }
   defer fields.Close()

   // do something with `fields`

}
ログイン後にコピー

遅延配置の 2 つのオプションが現れます:

  1. ループ本体内の遅延:

    for rows.Next() {
    
       fields, err := db.Query(.....)
       if err != nil {
          // ...
       }
    
       // do something with `fields`
    }
    
    defer fields.Close()
    ログイン後にコピー
  2. ループ後に延期body:

    for rows.Next() {
    
       fields, err := db.Query(.....)
       if err != nil {
          // ...
       }
       
       // do something with `fields`
       
       defer fields.Close()
    }
    ログイン後にコピー

実行の遅延について

最適なアプローチを選択するには、まず遅延の動作を理解する必要があります。遅延関数は、周囲の関数が戻るまで遅延されるだけでなく、関数が例外 (パニックなど) により突然終了した場合でも実行されます。これは、例外的な状況でも確実にリソースを解放するための重要なメカニズムとして機能します。

遅延配置に関する潜在的な問題

ループ内に遅延を配置すると、ループ終了時のリソース解放が妨げられる可能性があります。 。ループ内で処理されたエラーによりループが早期に終了した場合、遅延された field.Close() 呼び出しは実行されません。

逆に、ループ本体の後に defer を配置すると、方法に関係なくリソースが解放されることが保証されます。ループが終了します。ただし、このアプローチでは、ループ全体が完了するまでリソースのクリーンアップが遅延するため、すべてのシナリオで望ましいとは限りません。

最適な解決策: 匿名または名前付き関数ラッパー

両方の問題に対処するには、リソースの割り当てと解放を匿名関数または名前付き関数内でカプセル化することが推奨される解決策です。そうすることで、関数内で defer を使用して、関数の戻り時にリソースを確実に解放できます。

例:

// Anonymous function wrapper
for rows.Next() {
    func() {
        fields, err := db.Query(...)
        if err != nil {
            // Handle error and return
            return
        }
        defer fields.Close()

        // do something with `fields`
    }()
}

// Named function wrapper
func foo(rs *db.Rows) {
    fields, err := db.Query(...)
    if err != nil {
        // Handle error and return
        return
    }
    defer fields.Close()

    // do something with `fields`
}

for rows.Next() {
    foo(rs)
}
ログイン後にコピー

このアプローチでは、リソースがなくなるとすぐにリソースを解放できます。例外の場合でも必要です。さらに、最初のエラーでループを終了することが目的の場合は、ラッパー関数からエラーを返し、それに応じて処理できます。

func foo(rs *db.Rows) error {
    fields, err := db.Query(...)
    if err != nil {
        return fmt.Errorf("db.Query error: %w", err)
    }
    defer fields.Close()

    // do something with `fields`
    return nil
}

for rows.Next() {
    if err := foo(rs); err != nil {
        // Handle error and return
        return
    }
}
ログイン後にコピー

Rows.Close()

Rows.Close() はエラーを返すことに注意することが重要です。このエラーを処理するには、Rows.Close() への遅延呼び出しを持つ匿名関数を使用できます:

以上がGo でリソースを適切に解放するには、ループ内のどこに「defer」ステートメントを配置すればよいですか?の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

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