Skip to content

defer

Go ์–ธ์–ด์˜ defer ๋ฌธ๋ฒ•๊ณผ ํ™œ์šฉ

Section titled โ€œGo ์–ธ์–ด์˜ defer ๋ฌธ๋ฒ•๊ณผ ํ™œ์šฉโ€

Go ์–ธ์–ด๋Š” ๋ฆฌ์†Œ์Šค ์ •๋ฆฌ์™€ ์˜ˆ์™ธ ์ฒ˜๋ฆฌ์˜ ๋‹จ์ˆœํ™”์— ํฐ ๊ฐ€์น˜๋ฅผ ๋‘๋ฉฐ, ์ด๋ฅผ ๋Œ€ํ‘œํ•˜๋Š” ๋ฌธ๋ฒ•์ด defer์ด๋‹ค. defer๋Š” ํ•จ์ˆ˜ ์‹คํ–‰์ด ๋๋‚˜๊ธฐ ์ง์ „ ์˜ˆ์•ฝ๋œ ๋™์ž‘์„ ์ˆ˜ํ–‰ํ•œ๋‹ค. ์ด ๋ฌธ๋ฒ•์€ Python์˜ with ๊ตฌ๋ฌธ์ด๋‚˜ Java, C++์˜ try/finally ๊ตฌ๋ฌธ๊ณผ ์œ ์‚ฌํ•œ ์—ญํ• ์„ ํ•˜๋ฉด์„œ๋„ Go๋‹ค์šด ๊ฐ„๊ฒฐํ•จ์„ ์œ ์ง€ํ•œ๋‹ค.


defer๋Š” ํ˜ธ์ถœ๋œ ์ˆœ์„œ๋Œ€๋กœ ์Šคํƒ์— ์Œ“์ด๊ณ , ํ•จ์ˆ˜๊ฐ€ ์ข…๋ฃŒ๋  ๋•Œ ์—ญ์ˆœ์œผ๋กœ ์‹คํ–‰๋œ๋‹ค. ๋‹ค์Œ ์˜ˆ์ œ๋Š” ์ด ์›๋ฆฌ๋ฅผ ์ง๊ด€์ ์œผ๋กœ ๋ณด์—ฌ์ค€๋‹ค.

package main
import "fmt"
func main() {
fmt.Println("start")
defer fmt.Println("first defer")
defer fmt.Println("second defer")
defer fmt.Println("third defer")
fmt.Println("end")
}

์‹คํ–‰ ๊ฒฐ๊ณผ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.

start
end
third defer
second defer
first defer

๋ฆฌ์†Œ์Šค ์ •๋ฆฌ์—์„œ์˜ ํ™œ์šฉ

Section titled โ€œ๋ฆฌ์†Œ์Šค ์ •๋ฆฌ์—์„œ์˜ ํ™œ์šฉโ€

๋ฆฌ์†Œ์Šค ํ•ด์ œ๋Š” ํ•จ์ˆ˜ ๋ณธ๋ฌธ์—์„œ ์—ฌ๋Ÿฌ ์ง€์ ์— return์ด ๋“ฑ์žฅํ•  ๋•Œ ํŠนํžˆ ์ทจ์•ฝํ•˜๋‹ค. defer๋ฅผ ํ™œ์šฉํ•˜๋ฉด ๋ฆฌ์†Œ์Šค๋ฅผ ํš๋“ํ•œ ์‹œ์ ์—์„œ ์ •๋ฆฌ ์ ˆ์ฐจ๋ฅผ ์˜ˆ์•ฝํ•  ์ˆ˜ ์žˆ์–ด ์ฝ”๋“œ์˜ ์‹ ๋ขฐ์„ฑ์„ ๋†’์ธ๋‹ค.

func readFile(name string) ([]byte, error) {
f, err := os.Open(name)
if err != nil {
return nil, err
}
defer f.Close()
return io.ReadAll(f)
}

๋ฝ ํ•ด์ œ์—์„œ๋„ ๋™์ผํ•œ ํŒจํ„ด์ด ์“ฐ์ธ๋‹ค.

func updateSharedData(mu *sync.Mutex, data *int) {
mu.Lock()
defer mu.Unlock()
*data++
}

defer๋Š” ๋‹จ์ผ ํ˜ธ์ถœ๋ฟ ์•„๋‹ˆ๋ผ ์—ฌ๋Ÿฌ ์ค„์˜ ์ •๋ฆฌ ๋กœ์ง๋„ ์˜ˆ์•ฝํ•  ์ˆ˜ ์žˆ๋‹ค. ์ด๋•Œ ์ต๋ช… ํ•จ์ˆ˜๋ฅผ ํ™œ์šฉํ•œ๋‹ค.

defer func() {
fmt.Println("cleanup start")
recover()
fmt.Println("cleanup done")
}()

์ด ๋ฐฉ์‹์€ ๋กœ์ปฌ ๋ณ€์ˆ˜๋ฅผ ์บก์ฒ˜ํ•˜๊ฑฐ๋‚˜ panic์„ ๋ณต๊ตฌํ•˜๋Š” ๋ฐ ์œ ์šฉํ•˜๋‹ค.


๋ฃจํ”„์—์„œ defer๋ฅผ ์‚ฌ์šฉํ•  ๋•Œ๋Š” ๋ณ€์ˆ˜ ์บก์ฒ˜ ๋ฐฉ์‹์— ์ฃผ์˜ํ•ด์•ผ ํ•œ๋‹ค. ์ต๋ช… ํ•จ์ˆ˜๊ฐ€ ๋ณ€์ˆ˜๋ฅผ ์ง์ ‘ ์บก์ฒ˜ํ•˜๋ฉด ๋ฐ˜๋ณต๋ฌธ ์ข…๋ฃŒ ์‹œ์ ์˜ ์ตœ์ข… ๊ฐ’์ด ๋ฐ˜์˜๋œ๋‹ค.

for i := 0; i < 3; i++ {
defer func() {
fmt.Println("wrong:", i)
}()
}

์œ„ ์ฝ”๋“œ๋Š” 3์„ ์„ธ ๋ฒˆ ์ถœ๋ ฅํ•œ๋‹ค. ์˜๋„ํ•œ ๊ฐ’์„ ์ถœ๋ ฅํ•˜๋ ค๋ฉด ์ธ์ž ์ „๋‹ฌ์„ ํ†ตํ•ด ๊ฐ’์„ ๋ณต์‚ฌํ•ด์•ผ ํ•œ๋‹ค.

Go 1.22+: Go 1.22๋ถ€ํ„ฐ ๋ฃจํ”„ ๋ณ€์ˆ˜์˜ ์Šค์ฝ”ํ•‘์ด ๋ณ€๊ฒฝ๋˜์–ด, ๊ฐ ๋ฐ˜๋ณต(iteration)๋งˆ๋‹ค ๋ณ€์ˆ˜์˜ ์ƒˆ ์ธ์Šคํ„ด์Šค๊ฐ€ ์ƒ์„ฑ๋œ๋‹ค. ๋”ฐ๋ผ์„œ Go 1.22 ์ด์ƒ์—์„œ๋Š” ์œ„์˜ โ€œ์ž˜๋ชป๋œโ€ ์˜ˆ์ œ๋„ ์˜ฌ๋ฐ”๋ฅด๊ฒŒ 2, 1, 0์„ ์ถœ๋ ฅํ•œ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ์ด์ „ ๋ฒ„์ „๊ณผ์˜ ํ˜ธํ™˜์„ฑ์„ ์œ„ํ•ด ์ธ์ž ์ „๋‹ฌ ๋ฐฉ์‹์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ์—ฌ์ „ํžˆ ๊ถŒ์žฅ๋œ๋‹ค.

for i := 0; i < 3; i++ {
defer func(val int) {
fmt.Println("correct:", val)
}(i)
}

ํ•จ์ˆ˜ ์‹คํ–‰ ์ค‘ panic์ด ๋ฐœ์ƒํ•ด๋„ defer๋Š” ๋ณด์žฅ๋œ๋‹ค. ๋”ฐ๋ผ์„œ cleanup ๋กœ์ง์€ ํ•ญ์ƒ ์‹คํ–‰๋œ๋‹ค.

func main() {
defer fmt.Println("cleanup 1")
defer fmt.Println("cleanup 2")
fmt.Println("before panic")
panic("something went wrong")
}

์ถœ๋ ฅ์€ ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.

before panic
cleanup 2
cleanup 1
panic: something went wrong

defer๋Š” named return ๊ฐ’์„ ์ˆ˜์ •ํ•˜๋Š” ๋ฐ๋„ ์“ฐ์ผ ์ˆ˜ ์žˆ๋‹ค.

func f() (n int) {
defer func() { n += 10 }()
n = 5
return
}
func main() {
fmt.Println(f()) // 15
}

์ด ๊ธฐ๋Šฅ์€ ์‹ ์ค‘ํ•˜๊ฒŒ ์‚ฌ์šฉํ•  ํ•„์š”๊ฐ€ ์žˆ๋‹ค. ์˜๋„๊ฐ€ ๋ช…ํ™•ํ•˜์ง€ ์•Š์œผ๋ฉด ๊ฐ€๋…์„ฑ์„ ํ•ด์น  ์ˆ˜ ์žˆ๋‹ค.


defer๋Š” ๋ฆฌ์†Œ์Šค ์ •๋ฆฌ์™€ ์˜ˆ์™ธ ์•ˆ์ „์„ฑ์„ ๋‹จ์ˆœํ•œ ๊ตฌ๋ฌธ์œผ๋กœ ํ•ด๊ฒฐํ•˜๋Š” Go ์–ธ์–ด์˜ ์ค‘์š”ํ•œ ์žฅ์น˜์ด๋‹ค. ๋ฆฌ์†Œ์Šค๋ฅผ ํš๋“ํ•œ ์ฆ‰์‹œ ์ •๋ฆฌ๋ฅผ ์˜ˆ์•ฝํ•˜๋Š” ์Šต๊ด€์€ ์•ˆ์ „ํ•œ ์ฝ”๋“œ ์ž‘์„ฑ์„ ๋•๋Š”๋‹ค. defer๋Š” ์Šคํƒ ๊ธฐ๋ฐ˜ ์‹คํ–‰, ์ต๋ช… ํ•จ์ˆ˜ ํ™œ์šฉ, panic ๋ณต๊ตฌ ์ง€์› ๋“ฑ์„ ํ†ตํ•ด Python์˜ ์ปจํ…์ŠคํŠธ ๋งค๋‹ˆ์ €์™€ ๊ฐ™์€ ์—ญํ• ์„ ์ˆ˜ํ–‰ํ•˜๋ฉด์„œ๋„ Go์˜ ๊ฐ„๊ฒฐํ•œ ์ฒ ํ•™์„ ์ž˜ ๋ณด์—ฌ์ค€๋‹ค.