NullNull

Go lang : defer 키워드 본문

프로그래밍 언어/GO

Go lang : defer 키워드

KYBee 2022. 10. 23. 17:29

defer 

  • 함수나 코드의 실행을 가장 마지막까지 미룰 수 있음
  • defer 키워드가 있는 함수나 코드는 실행이 바로 되지 않고 그 함수의 실행이 끝난 후 LIFO 방식으로 실행됨
package main

import "fmt"

func d1() {
	fmt.Println("d1 function")
	for i := 3; i > 0; i-- {
		defer fmt.Print(i, " ")
	}
}

func d2() {
	fmt.Println("d2 function")
	for i := 3; i > 0; i-- {
		defer func() {
			fmt.Print(i, " ")
		}()
	}
}

func d3() {
	fmt.Println("d3 function")
	for i := 3; i > 0; i-- {
		defer func(n int) {
			fmt.Print(n, " ")
		}(i)
	}
}

func main() {
	d1()
	fmt.Println()
	d2()
	fmt.Println()
	d3()
	fmt.Println()
}

 

d1 함수

3부터 1까지 실행하면서 i를 출력한다. 이때 출력하는 코드 앞에 defer을 적었기 때문에, 해당 코드는 d1함수가 종료될 때 실행된다. defer 키워드를 만나 가장 최근에 실행을 미루었던 코드부터 실행된다.

만나는 순서

  1. defer fmt.Print(3, " ")
  2. defer fmt.Print(2, " ")
  3. defer fmt.Print(1, " ")

위의 순서대로 함수를 만나기 때문에 실행될 때는 가장 최근에 실행이 미루어진 fmt.Print(1, “ ”) 가 실행된다.

실행 순서

  1. fmt.Print(1, " ")
  2. fmt.Print(2, " ")
  3. fmt.Print(3, " ")

실행 결과

d1 function
1 2 3

d2 함수

d1 함수와 실행이 비슷하다. 하지만 이 경우에는 익명 함수 앞에 defer 키워드를 적었으므로 익명 함수의 실행이 미루어진다. 함수의 실행 순서를 세분화 하면 다음과 같다.

실행 순서

  1. d2 function을 출력한다.
  2. for문에 들어간다.
  3. i가 3이다. 이때 defer 함수 뒤의 익명함수는 실행이 미루어진다.
  4. i가 2이다. 이때 defer 함수 뒤의 익명함수는 실행이 미루어진다.
  5. i가 1이다. 이때 defer 함수 뒤의 익명함수는 실행이 미루어진다.
  6. for문을 벗어난다.
  7. 이제 미루었던 함수를 실행한다.
  8. i가 1일때 미루어졌던 익명함수를 실행한다. i값을 출력해야 한다. for문이 끝남과 동시에 i에는 0이 할당되어 있다. (i가 1인 상황에서 i— 연산을 통해 0으로 바뀐 뒤 for문을 벗어났기 때문이다.) for 문이 끝나서 i에 더이상 1이 할당되어있지 않다. 이에 0을 출력한다.
  9. i가 2일때 미루어졌던 익명함수를 실행한다. i값을 출력해야 한다. for문이 끝남과 동시에 i에는 0이 할당되어 있다. (i가 1인 상황에서 i— 연산을 통해 0으로 바뀐 뒤 for문을 벗어났기 때문이다.) for 문이 끝나서 i에 더이상 2이 할당되어있지 않다. 이에 0을 출력한다.
  10. i가 3일때 미루어졌던 익명함수를 실행한다. i값을 출력해야 한다. for문이 끝남과 동시에 i에는 0이 할당되어 있다. (i가 1인 상황에서 i— 연산을 통해 0으로 바뀐 뒤 for문을 벗어났기 때문이다.) for 문이 끝나서 i에 더이상 3이 할당되어있지 않다. 이에 0을 출력한다.

실행 결과

d2 function
0 0 0

실행이 미루어진 익명 함수가 for 루프가 끝난 뒤에 평가받는다. 이 함수는 매개변수를 받지 않기 때문에 i가 0인 상태에서 3번 출력된 것 이다.

d3 함수

d2 함수와 실행이 비슷하다. 하지만 이 경우에는 익명 함수에게 별도의 매개변수를 전달한다. 함수의 실행 순서를 세분화 하면 다음과 같다.

실행 순서

  1. d3 function을 출력한다.
  2. for문에 들어간다.
  3. i가 3이다. 이때 defer 함수 뒤의 익명함수는 매개변수 3과 함께 실행이 미루어진다.
  4. i가 2이다. 이때 defer 함수 뒤의 익명함수는 매개변수 2와 함께 실행이 미루어진다.
  5. i가 1이다. 이때 defer 함수 뒤의 익명함수는 매개변수 1과 함께 실행이 미루어진다.
  6. for문을 벗어난다.
  7. 이제 미루었던 함수를 실행한다.
  8. i가 1일때 미루어졌던 익명함수를 실행한다. n값을 출력해야 한다. 미루어졌을 당시의 n값 1을 기억하고 있으므로 1을 출력한다.
  9. i가 2일때 미루어졌던 익명함수를 실행한다. n값을 출력해야 한다. 미루어졌을 당시의 n값 2을 기억하고 있으므로 2을 출력한다.
  10. i가 3일때 미루어졌던 익명함수를 실행한다. n값을 출력해야 한다. 미루어졌을 당시의 n값 3을 기억하고 있으므로 3을 출력한다.

실행 결과

d3 function
1 2 3

매개변수를 받기 때문에, 매번 실행이 미루어질 때마다 현재 상태의 i 값을 가져와서 사용한다. 따라서 익명 함수가 실행될 때마다 처리할 값이 달라져서 다음과 같은 결과가 나온다.

 

 

💡 가장 바람직한 defer 사용 방법은 d3일 것이다. 원하는 변수를 명시적으로 익명 함수에 전달해 이해하기 쉽기 때문이다.

 

'프로그래밍 언어 > GO' 카테고리의 다른 글

Go routine이 무엇일까?  (0) 2022.10.23
Comments