FelixBaek

Go

Go defer는 값을 언제 기억할까?

defer에 넘긴 인자와 클로저가 같은 변수를 다르게 읽는 이유를 짧은 코드로 확인합니다.

약 1분
목차2개 섹션
  1. 같은 변수, 다른 결과
  2. 값을 지금 고정하려면

Go의 defer는 함수가 끝나기 직전에 실행됩니다. 다만 실행을 미룬다고 해서 값까지 나중에 정해지는 것은 아닙니다. 일반 함수 호출의 인자는 defer를 만난 순간 계산되고, 클로저 본문은 실제로 실행될 때 변수를 읽습니다.

같은 변수, 다른 결과

gomain.go
package main

import "fmt"

func main() {
	name := "first"
	defer fmt.Println("1:", name)

	name = "second"
	defer func() {
		fmt.Println("2:", name)
	}()

	name = "third"
}

실행 결과는 다음과 같습니다.

text
2: third
1: first

fmt.Println("1:", name)의 인자는 defer가 등록될 때 평가됩니다. 이때 name은 "first"이므로, 이후 변수를 바꿔도 저장된 값은 달라지지 않습니다.

두 번째 defer는 익명 함수의 실행만 미룹니다. 함수 본문에서 name을 읽는 시점에는 이미 값이 "third"로 바뀐 뒤입니다. 두 출력의 순서가 뒤집힌 이유는 나중에 등록한 defer부터 실행되기 때문입니다.

값을 지금 고정하려면

클로저에서도 현재 값을 기억하게 하려면 인자로 넘기면 됩니다.

go
defer func(saved string) {
	fmt.Println(saved)
}(name)

여기서 name은 defer를 등록하는 순간 saved에 전달됩니다. defer 안에서 바깥 변수를 바로 참조하는지, 인자로 넘기는지만 구분하면 실행 결과를 예상하기 쉬워집니다.

댓글

GitHub 계정으로 댓글을 남길 수 있습니다.