この記事は、go 言語 チュートリアル コラムによって紹介されています。トピックは go defer の学習と使用についてです。困っている友人の役に立てば幸いです。 !
延期とは何ですか?
Go では、関数呼び出しを defer
キーワードに続けて遅延関数呼び出しを形成できます。
関数呼び出しが遅延すると、すぐには実行されません。これは、現在のコルーチンによって維持される遅延呼び出しスタックにプッシュされます。関数呼び出し (遅延呼び出しである場合もそうでない場合もある) が戻って終了フェーズに入ると、この関数呼び出し内でプッシュされたすべての遅延呼び出しは、スタックにプッシュされた順序とは逆の順序で実行されます。 。これらの遅延呼び出しがすべて実行されると、関数呼び出しは実際に終了します。
簡単な例:
package mainimport "fmt"func sum(a, b int) { defer fmt.Println("sum函数即将返回") defer fmt.Println("sum函数finished") fmt.Printf("参数a=%v,参数b=%v,两数之和为%v\n", a, b, a+b)}func main() { sum(1, 2)}
出力:
参数a=1,参数b=2,两数之和为3 sum函数finished sum函数即将返回
実際、各コルーチンは 2 つのコール スタックを維持します。
関数パラメータの評価を遅延する
package mainimport "fmt"func Print(a int) {fmt.Println("defer函数中a的值=", a)}func main() {a := 10defer Print(a)a = 1000fmt.Println("a的值=", a)}
output:
a的值= 1000 defer函数中a的值= 10
defer Print(a) 遅延呼び出しスタックに追加されるとき、a の値は 5 なので、defer Print (a) 出力結果は 5
Example 2:
package mainimport "fmt"func main() { func() { for i := 0; i < 3; i++ { defer fmt.Println("a=", i) } }() fmt.Println() func() { for i := 0; i < 3; i++ { defer func() { fmt.Println("b=", i) }() } }()}
output:
a= 2 a= 1 a= 0 b= 3 b= 3 b= 3
i になります。最初の匿名関数ループは、fmt.Println 関数の実行中に遅延呼び出しスタックにプッシュされます。 call のときに推定される値なので、出力結果は 2, 1, 0 になります。 2 番目の無名関数の i は、無名関数呼び出しの終了フェーズで推定される値 (この時点で i は 3 になっています) なので、出力結果はは: 3、3、3。
実際には、2 番目の無名関数呼び出しを少し変更することで、無名関数 1 つ目と同じ結果を出力させることができます。
package mainimport "fmt"func main() { func() { for i := 0; i < 3; i++ { defer fmt.Println("a=", i) } }() fmt.Println() func() { for i := 0; i < 3; i++ { defer func(i int) { fmt.Println("b=", i) }(i) } }()}
output:
a= 2 a= 1 a= 0 b= 2 b= 1 b= 0
パニックとリカバリ(遅延回復)
Go は例外のスローとキャッチをサポートしていませんが、戻り値を使用して明示的にエラーを返すことをお勧めします。ただし、Go は例外のスロー/キャッチと同様のメカニズムをサポートしています。このメカニズムは、パニック/リカバリ メカニズムと呼ばれます。
組み込み関数 panic
を呼び出してパニックを生成し、現在のコルーチンがパニック状態になるようにします。
パニック状態に入るということは、現在の関数呼び出しの戻りを開始させるもう 1 つの方法です。関数呼び出しがパニックを生成すると、関数呼び出しはすぐに終了フェーズに入り、関数呼び出し内のスタックにプッシュされた遅延呼び出しは、プッシュされた順序とは逆の順序で実行されます。
遅延関数呼び出し内で組み込み関数 recover
を呼び出すことで、現在のコルーチンのパニックを解消し、現在のコルーチンを通常の状態に戻すことができます。
パニック状態のコルーチンが終了するまでは、パニックは他のコルーチンに広がりません。コルーチンがパニック状態で終了すると、プログラム全体がクラッシュします。次の 2 つの例を見てください。
package mainimport ( "fmt" "time")func p(a, b int) int { return a / b}func main() { go func() { fmt.Println(p(1, 0)) }() time.Sleep(time.Second) fmt.Println("程序正常退出~~~")}
output:
panic: runtime error: integer pide by zero goroutine 6 [running]: main.p(...) /Users/didi/Desktop/golang/defer.go:9 main.main.func1() /Users/didi/Desktop/golang/defer.go:14 +0x12 created by main.main /Users/didi/Desktop/golang/defer.go:13 +0x39exit status 2
p 関数がパニックになります (除数が 0)。コルーチンにはパニック回復メカニズムがないため、プログラム全体がクラッシュします。
p 関数が配置されているコルーチンにパニック リカバリ (遅延リカバリ) が追加されている場合、プログラムは正常に終了できます。
package mainimport ( "fmt" "time")func p(a, b int) int { return a / b}func main() { go func() { defer func() { v := recover() if v != nil { fmt.Println("恐慌被恢复了:", v) } }() fmt.Println(p(1, 0)) }() time.Sleep(time.Second) fmt.Println("程序正常退出~~~")}
output:
恐慌被恢复了: runtime error: integer pide by zero 程序正常退出~~~
Golang 関連の知識については、golangチュートリアル列をご覧ください! ##
以上がGo の遅延とは何ですか?使い方?の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。