ホームページ  >  記事  >  バックエンド開発  >  Go 言語における遅延とパニックの関係は何ですか?

Go 言語における遅延とパニックの関係は何ですか?

王林
王林オリジナル
2023-06-11 09:00:08861ブラウズ

Go 言語は、いくつかの独自の構文と機能が追加された新しいプログラミング言語です。そのうちの 2 つの非常に重要な機能は、defer と Panic です。この記事ではGo言語におけるdeferとpanicの関係や使い方、特徴について紹介します。

deferの使い方

Go言語のdefer文は関数を登録するために使用され、この関数の実行が終了するか、現在のスコープが終了すると、登録した関数が自動的に実行されます。 defer は、リソースの解放、ロックのロック解除、エラー処理などの複数のシナリオで使用できます。

以下はリソースの遅延解放の例です。

func main() {
    file, err := os.Open("myfile.txt")
  // 在函数结束时,会自动关闭文件
    defer file.Close()
  
    if err != nil {
        fmt.Println("Failed to open file.")
        return
    }
    // ...
}

これは遅延ファイルの Close() 関数を通じて登録され、関数の実行が終了するとファイルは自動的に閉じられます。

以下は遅延ロックのロックを解除する例です:

func main() {
    var lock sync.Mutex
    lock.Lock()
  // 当函数执行结束时,会自动解锁
    defer lock.Unlock()
  
    // ...
}

関数の実行が終了すると、Unlock() 関数が自動的に呼び出され、ロックのロックが解除されます。

defer の実行順序は後から前です。つまり、複数の defer ステートメントが登録されている場合は、逆の順序で実行されます。次の例では、Defer 2 が出力され、次に Defer 1 が出力されます。

func main() {
    defer fmt.Println("Defer 1")
    defer fmt.Println("Defer 2")
    fmt.Println("Hello")
}

パニックの使用法

Go 言語のパニック キーワードは、例外をスローして現在の関数またはプログラムの実行を終了するために使用されます。パニックは、recover() 関数によって捕捉されるまで、関数呼び出しスタックを上に伝播します。キャッチされなかった場合は、プログラム全体が終了し、呼び出しスタックが出力されます。

次のコード例では、入力文字列の長さが 5 未満の場合、パニックがトリガーされ、プログラムの実行が終了します。

func hello(name string) {
    if len(name) < 5 {
        panic("Name is too short.")
    }
    fmt.Println("Hello", name)
}

func main() {
    hello("Tom")
    hello("Bob")
    hello("me")
}

出力結果は次のとおりです。

Hello Tom
Hello Bob
panic: Name is too short.

goroutine 1 [running]:
main.hello(...)
    /Users/user/goland/src/main.go:4
main.main()
    /Users/user/goland/src/main.go:10 +0x81
exit status 2

ここでは、入力名が me の場合、パニックがトリガーされ、プログラムの実行が終了することがわかります。

遅延とパニックの関係

パニックはプログラムの実行を即時に終了する役割を果たします。つまり、関数の実行の終了前を含め、いつでもトリガーできることを意味します。プログラムが時間内にリソースを解放し、必要なクリーンアップ作業を実行できるようにするために、Go 言語には遅延メカニズムが導入されており、関数が終了する前にいくつかのクリーンアップ操作を実行できるようになります。

関数内でパニックがトリガーされると、関数はただちに終了し、現在の関数の前に登録されているすべての遅延関数を実行します。次のコード例では、手動でパニックをトリガーし、終了する前に defer 関数を 2 回実行します。

func main() {
    defer fmt.Println("Defer 1")
    defer fmt.Println("Defer 2")
    
    panic("Oops! Something went wrong.")
}

出力結果は次のとおりです:

Defer 2
Defer 1
panic: Oops! Something went wrong.

goroutine 1 [running]:
main.main()
    /Users/user/goland/src/main.go:7 +0x81
exit status 2

パニックをトリガーした後、2 つの遅延関数が逆の順序で実行されることがわかります。

Go 言語では、関数の最後に defer 関数を登録するだけでなく、関数内に複数の defer 関数を登録することもできます。これは、関数内に複数の遅延関数がある場合、そのうちの 1 つの遅延関数がパニックをトリガーしたとしても、他の遅延関数は引き続き実行できることを意味します。

次のコード例は、関数が複数の defer ステートメントを登録すると、defer 関数の 1 つがパニックをトリガーしても、他の defer 関数は引き続き実行されることを示しています。

func init() {
    fmt.Println("Init 1")
}

func init() {
    fmt.Println("Init 2")
}

func main() {
    defer fmt.Println("Defer 1")
    
    defer func() {
        if err := recover(); err != nil {
            fmt.Println("Recovered:", err)
        }
    }()
    
    defer fmt.Println("Defer 2")
    
    panic("Oops! Something went wrong.")
}

出力結果は次のとおりです。

Init 1
Init 2
Defer 2
Recovered: Oops! Something went wrong.
Defer 1

関数が最初に 2 つの init 関数を実行し、次に 3 つの defer 関数を順番に実行していることがわかります。いずれかの遅延がパニックをトリガーしても、別の遅延によってキャッチされてプログラムが再開されると、最終的には両方の遅延関数が正常に実行されます。

実際の開発では、defer と Panic がペアで使用されることが多く、defer はリソースの解放とクリーンアップ操作に使用され、panic は例外処理に使用されます。関数が終了する前に複数のクリーンアップ操作を実行する必要がある場合、関数の先頭で defer ラッパー関数を使用し、recover() 関数を使用して関数が早期に終了するのを防ぐことができます。この書き方は非常に一般的であり、堅牢なプログラムを作成するための強力な保証を提供します。

以上がGo 言語における遅延とパニックの関係は何ですか?の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

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