Go インタビューの質問トピック (1): 理解している Golang defer キーワードについて話す

私たちの仕事でもよく使われるGo言語の特徴であり、面接官も好む知識ポイントでもあるdeferキーワードを、今回はこの記事を通して徹底的にマスターしていきます。

面接質問資料を無料でダウンロードするにはここをクリックしてください

Go 言語の初心者から熟練者まで、ここをクリックして無料でダウンロードしてください。

defer2 つの主要な機能

defer は golang のキーワードであり、主に次の 2 つの大きな特徴があります。

- 遅延呼び出し: 現在の関数の実行が完了した後に呼び出しを実行します。

func f1(){
    
    
	defer fmt.Println("hello world")

	fmt.Println("hello defer!")
}

出力結果:

$ go run main.go
hello defer!
hello world

後入れ先出し: 複数の遅延関数がある場合、実行順序は後入れ先出しになります。

func f2(){
    
    
	defer fmt.Println("hello 1!")
	defer fmt.Println("hello 2!")
	defer fmt.Println("hello 3!")

	fmt.Println("hello defer!")
}

出力結果

$ go run main.go
hello defer!
hello 3!
hello 2!
hello 1!

延期と返却の実行順序

延期と返却の実行順序は面接でよく検討される点であり、道教者はよく理解する必要があります。

まず、例を挙げて、次の状況でのコードの出力を見てみましょう。

func f1() (r int){
    
    
	defer func(){
    
    
		r++
	}()
	return 0
}

func f2() (r int) {
    
    
	t:=5
	defer func() {
    
    
		t = t+5
	}()
	return t
}

func f3() (r int) {
    
    
	defer func(r int) {
    
    
		r = r+5
	}(r)
	return 0
}

func main(){
    
    
	fmt.Println(f1())
	fmt.Println(f2())
	fmt.Println(f3())
}

友達が最初に答えを考えてから、後で見ることをお勧めします。

$ go run main.go
1
5
0

同じ道士の張三さんはこう思った、「くそー、冗談でしょ? 0、10、5 じゃないの…」

さて、それらを 1 つずつ分析しましょう。

ここでは、まず return ステートメントの実行順序を理解する必要があります。

return ステートメント自体はアトミック命令ではなく、次のように、最初に戻り値に値を代入してから戻ります。

func f4() (r int) {
    
    
	return 1
}

//执行过程:
r:=1 //赋值
ret //执行返回

defer 式が含まれている場合、関数の戻りプロセスは次のようになります。

最初に戻り値に値を代入し、次に defer 式を呼び出し、最後に結果を返します。

つまり、f1() の場合

func f1() (r int){
    
    
	defer func(){
    
    
		r++
	}()
	return 0
}

//执行过程:
r:=0 //赋值
r++  //defer
ret  //r=1

f2の場合

func f2() (r int) {
    
    
	t:=5
	defer func() {
    
    
		t = t+5
	}()
	return t
}

//执行过程
t:=5
r:=t
t=t+5 //defer
ret  //r=5

f3() の場合、遅延中に渡されるパラメータ r は実際には値のコピーです。

したがって、defer の r を変更しても戻り値の結果には影響せず、r を t に置き換えても結果は同じ、つまり以下と同等であることを理解するのに役立ちます。

func f3() (r int) {
    
    
	defer func(t int) {
    
    
		t = t+5
	}(r)
	return 0
}

//执行过程
r:=0
t = r, t = t +5 //defer
ret // r=0

延期の適用シナリオ

シナリオ 1: リソースの解放

ファイルを開くなど、コード内でリソースを使用する場合、解放し忘れたり、論理エラーが原因でリソースが閉じられなくなることがよくあります。この時点で defer を使用すると、このリソース リークを回避できます。まず次のコードを見てみましょう。

file,_ := os.Open("test.txt")
//process为业务逻辑处理
if err:=process(file);err!=nil {
    
    
  return
}
file.Close()

上記のコードには重大な問題があり、err!=nil を直接返すと、リソースをクローズする file.close() ステートメントが実行されず、リソース リークが発生します。
また、一連のビジネスロジックの処理を書いた後、リソースをクローズするのを忘れやすく、リソース漏洩が発生します。したがって、リソースの適用が成功するたびに自動的にクリーンアップするために defer を追加するという 1 つの原則を心に留めておく必要があります。関数の戻り数に関係なく、リソースは正しく解放されます。
正しい書き込みロジックは次のとおりです。

file,_ := os.Open("test.txt")
defer file.Close()
//process为业务逻辑处理
if err:=process(file);err!=nil {
    
    
  return
}

シナリオ 2: 例外のキャプチャ

Golang のプログラムの例外処理には、try catch はありませんが、panic とcover があります。プログラムでパニックが発生した場合、時間内に回復しないとサービスが直接ハングアップして重大な結果を引き起こすため、通常は例外をキャッチするために回復を使用します。

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

上記の 2 つのシナリオはよく理解しておく必要がありますが、もちろん、defer の機能を使用して、コード トレース、関数パラメーターと戻り値の記録などをエレガントに実装することもできます。

# シナリオ 3: コードの追跡

プログラムが関数に入る、または関数から出る情報を追跡することによって、この関数が実行されるかどうかをテストします。

func main(){
    
    
	f1()
	f2()
}

func f1(){
    
    
	defer trace_leave(trace_enter("f1()"))
	fmt.Println("f1()程序逻辑")
}

func f2(){
    
    
	defer trace_leave(trace_enter("f2()"))
	fmt.Println("f2()程序逻辑")
}

func trace_enter(msg string) string{
    
    
	fmt.Println("enter: ",msg)
	return msg
}

func trace_leave(msg string) {
    
    
	fmt.Println("leave: ",msg)
}

出力は次のとおりです。

$go run main.go
enter:  f1()
f1()程序逻辑
leave:  f1()
enter:  f2()
f2()程序逻辑
leave:  f2()

シナリオ 4: 関数のパラメーターと戻り値を出力する

特定の関数の実行結果が期待どおりではありません。defer を使用すると、デバッグ ステートメントを複数の場所に出力する代わりに、関数のパラメーターと戻り値を 1 つのステップで出力できます。

func main(){
    
    
	func1("hello")
}

func func1(str string) ( res string) {
    
    
	defer func() {
    
    
		fmt.Printf("func1(%s) = %s", str, res)
	}()
	res = fmt.Sprintf("%s, jack!",str)
	return
}

出力結果:

$go run main.go
func1(hello) = hello, jack!

面接のポイントまとめ

  • 遅延の 2 つの主な特徴
  • 延期と返却の実行順序
  • 延期の適用シナリオ

追記

この記事で紹介した面接テクニックについて質問がある場合は、コメント欄に返信して、一緒に学び、一緒に進歩していきましょう!

公開アカウント [Jiandao Programming] をフォローすると、毎日バックエンド技術面接ポイントがあります

おすすめ

転載: blog.csdn.net/m0_73728511/article/details/132767575