ホームページ  >  記事  >  バックエンド開発  >  golang の defer の主な機能の詳細な紹介

golang の defer の主な機能の詳細な紹介

巴扎黑
巴扎黑オリジナル
2017-08-12 14:41:561385ブラウズ

defer は golang 言語のキーワードで、リソースを解放するために使用され、関数が戻る前に呼び出されます。次の記事では、主に golang の defer の主要な機能をサンプル コードを通じて詳しく紹介しています。必要な方は以下を参照してください。

前書き

golang の defer キーワードは誰もが知っています。これは、関数が戻る前にいくつかの操作を実行できます。最も一般的に使用されるのは、リソース (ファイル、データベースなど) を開くときに閉じるのを遅らせるために defer を使用することです。接続など) メモリ リークを避けるためにリソースを変更します。この記事では、主に golang の defer の主要な機能を紹介し、参考と学習のために共有します。

1. defer の役割と実行タイミングを見てみましょう。

go の defer ステートメントは関数の実行を遅らせるために使用され、遅延は関数 return を呼び出した後に発生します。たとえば、


func a() int {
 defer b()
 return 0
}

b の実行は return 0 の後に発生します。 defer の構文。キーワード defer の後に関数呼び出しが続きます。

2. defer の重要な使用法 1: リソースのクリーンアップと解放

defer の遅延特性により、defer は、


などの関数呼び出し終了後に関連リソースをクリーンアップするためによく使用されます。

f, _ := os.Open(filename)
defer f.Close()

ファイルリソースの解放は、関数呼び出しが完了した後、defer を使用して自動的に実行されます。 リソースの解放が必要な場所を常に覚えておく必要はありません。

例を使用して、defer によってもたらされる利便性とシンプルさを深く説明します。

コードの主な目的は、ファイルを開いて、その内容を別の新しいファイルにコピーすることです。遅延がない場合は、次のように記述されます。


func CopyFile(dstName, srcName string) (written int64, err error) {
 src, err := os.Open(srcName)
 if err != nil {
  return
 }
 dst, err := os.Create(dstName)
 if err != nil { //1
  return
 }
 written, err = io.Copy(dst, src)
 dst.Close()
 src.Close()
 return
}

コードが #1 に戻った後、 src ファイルが閉じられていないため、リソースが正しく解放されない可能性があります。代わりに defer を使用してください: return がどこで実行されたとしても、src と dst は時間内にクリーンされて解放されます。

defer の役割を考慮すると、defer はデータベース接続、ファイル オープン ハンドル、およびリソースを解放するその他の操作を解放するためによく使用されます。


3. defer の重要な使い方 2: リカバリを実行する

defer 関数は return 後に実行されるので、関数によってスローされたパニックをキャプチャするのにちょうど良いタイミングなので、defer のもう 1 つの重要な使い方は実行することです。回復する 。 recover は、defer で使用する場合にのみ意味を持ちます。他の場所で使用すると、プログラムがすでに呼び出されており、早期に返されるため、エラーを効果的に捕捉できません。

func CopyFile(dstName, srcName string) (written int64, err error) {
 src, err := os.Open(srcName)
 if err != nil {
  return
 }
 defer src.Close()
 dst, err := os.Create(dstName)
 if err != nil {
  return
 }
 defer dst.Close()
 return io.Copy(dst, src)
}

defer はパニック実行の前に配置する必要があることに注意してください。


4. 複数の defer の実行順序

defer の機能は、キーワードの後の関数の実行をスタックにプッシュして実行を遅らせることです。複数の defer の実行順序は後入れ先出し LIFO です。

package main
import (
 "fmt"
)
func main() {
 defer func() {
  if ok := recover(); ok != nil {
   fmt.Println("recover")
  }
 }()
 panic("error")
}

出力シーケンスは 321 です。

この機能は、配列に対して逆順の演算を実装できます。


5. defer 関数のパラメータは defer 時に決定されます

これが defer の特徴であり、関数が defer されると、後でパラメータが変更されても、そのパラメータは defer 時に計算され決定されます。 defer、遅延された関数は効果がありません。これは何を意味しますか?例を見てください:

defer func() { fmt.Println("1") }()
defer func() { fmt.Println("2") }()
defer func() { fmt.Println("3") }()

a defer の場合、i の値は 0 で、defer 関数のパラメーターが計算されて決定されているため、実行出力は 1 ではなく 0 になります。

別の例を見てください:


func a() {
 i := 0
 defer fmt.Println(i)
 i++
 return
}

実行コード出力


func calc(index string, a, b int) int {
 ret := a + b
 fmt.Println(index, a, b, ret)
 return ret
}
func main() {
 a := 1
 b := 2
 defer calc("1", a, calc("10", a, b))
 a = 0
 return
}

defer 関数の 3 番目のパラメーターは defer 時に計算されて決定されており、2 番目のパラメーター a についても同じことが当てはまります。変数が変更されたかどうかは関係ありません。


6. 遅延関数は名前付き戻り値を読み取って変更できます

10 1 2 3 
1 1 3 4
遅延関数は return 後に実行され、名前付き戻り値を変更できます 上記の関数 c 返されるものは 2 です。 。

以上がgolang の defer の主な機能の詳細な紹介の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

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