Defer의 기본 사용

Divan·2023년 10월 31일
post-thumbnail

defer는 function이 return하기 직전에 실행한다. C#에서 유사한 문법으로는 finally가 있으며, 주로 메모리 활당해제와 같은 clean-up을 위해 사용된다. 예를 들어 파일 읽기와 같은 작업을 수행할 때 defer를 사용하여 file을 open 후 다음 라인에서 defer close를 작성하여 추후에 close하는 것을 망각하는 것을 방지 가능하다.


일반적인 사용

파일을 오픈 후 defer를 이용하여 function(TestFileOpen) return 직전 f.close()를 호출

func TestFileOpen(t *testing.T) {
	fileName := "./test.txt"
	f, _ := os.Open(fileName)
	defer f.Close()
	contents, err := io.ReadAll(f)
	if err != nil {
		t.Error(err)
	}
	t.Log(string(contents))
}

defer의 특성

1.선입 후출(FILO) 방식으로 동작

2.종속해 있는 function의 retrun 직전에 실행한다.

3.defer fn()에서 전달되는 Parameter는 defer의 선언된 라인의 parameter의 상태가 전달된다. 파라미터로 전달되지 않은 값은 fn의 return직전의 값을 참조한다.

func TestParameter(t *testing.T) {
	num := 0
	fmt.Printf("currnet num : %v \n", num)
	defer func(val int) {
		fmt.Printf("first func i : %v \n", num)
		fmt.Printf("first func value : %v \n", val)
	}(num)
	for i := 0; i < 10; i++ {
		num++
	}
	defer func(val int) {
		fmt.Printf("second func i : %v \n", num)
		fmt.Printf("second func value : %v \n", val)
	}(num)
}

4.return은 defer보다 먼저 실행된다.

func TestDeferAndReturn(t *testing.T) {
	func() (int, error) {
		defer fmt.Println("defer")
		return fmt.Println("function")
	}()
}
!

5.Panic 발행 시, 현재 stack에 쌓여있는 것들만 LIFO 순서로 실행된다.

func TestDeferPanic(t *testing.T) {
	defer printOut("a")
	defer printOut("b")
	defer printOut("c")

	panic("panic here")
	defer printOut("d")
	printOut("end of function")
}


결론

defer mu.unlock과 같이 defer를 사용하면 코드가 더욱 깔끔해지고, 실수를 줄일 수 있다. 하지만 특성을 잘 모른다면 실수하기 쉬움, 특히 변수를 전달할 때는 명확하게 사용하여야 한다.

profile
하루 25분의 투자

1개의 댓글

comment-user-thumbnail
2023년 11월 1일

갈수록 포스팅 퀄이 좋아지네요 잘보고 갑니다

답글 달기