개발/GO
[Golang] defer
피클s
2022. 4. 4. 20:34
이 글은 Defer keyword in Go (Golang) - Welcome To Golang By Example 을 번역 및 재가공하여 작성하였습니다.
목차
1. defer 키워드란?
defer의 사전적 의미는 미루다, 연기하다 입니다.
defer는 선언된 함수가 끝나기 직전에 실행됩니다.
defer는 에러가 발생하여 비정상 종료가 될 때에도 실행됩니다.
그래서 io를 close 하거나 에러를 캐치할 때에 사용됩니다.
package main
import (
"fmt"
"log"
"os"
)
func main() {
err := writeToTempFile("Some text")
if err != nil {
log.Fatalf(err.Error())
}
fmt.Printf("Write to file succesful")
}
func writeToTempFile(text string) error {
file, err := os.Open("temp.txt")
if err != nil {
return err
}
defer file.Close()
n, err := file.WriteString("Some text")
if err != nil {
return err
}
fmt.Printf("Number of bytes written: %d", n)
return nil
}
2. 여러 형태의 실행방법
2-1. 함수 실행
package main
import "fmt"
func main() {
defer test()
fmt.Println("Executed in main")
}
func test() {
fmt.Println("In Defer")
}
Executed in main
In Defer
2-2. 인라인 함수 실행
인라인 함수는 끝에 ()를 붙여야 정상적으로 실행됩니다.
package main
import "fmt"
func main() {
defer func() { fmt.Println("In inline defer") }()
fmt.Println("Executed")
}
Executed
In inline defer
3. defer가 작동하는 방식
defer는 내부적으로 스택 데이터구조로 이루어져있습니다.
여러 defer가 선언되어 있다면 FILO(First In Last Out)순서로 실행됩니다.
package main
import "fmt"
func main() {
defer fmt.Println("Defer in main")
fmt.Println("Stat main")
f1()
fmt.Println("Finish main")
}
func f1() {
defer fmt.Println("Defer in f1")
fmt.Println("Start f1")
f2()
fmt.Println("Finish f1")
}
func f2() {
defer fmt.Println("Defer in f2")
fmt.Println("Start f2")
fmt.Println("Finish f2")
}
Stat main
Start f1
Start f2
Finish f2
Defer in f2
Finish f1
Defer in f1
Finish main
Defer in main
4. 파라메터가 실행되는 타이밍
package main
import "fmt"
func main() {
sample := "abc"
defer fmt.Printf("In defer sample is: %s\n", sample)
sample = "xyz"
}
In defer sample is: abc
defer가 출력한 sample은 abc였습니다.
main함수가 종료될 때 sample은 xyz이지만 defer가 스택에 들어갈 때는 abc 이기때문에
abc가 실행됩니다.
5. defer와 named return value
named return value 의 경우 defer에서 값이 수정될 수 있습니다.
package main
import "fmt"
func main() {
s := test()
fmt.Println(s)
}
func test() (size int) {
defer func() { size = 20 }()
size = 30
return
}
20
6. defer와 panic
panic이 발생하더라도 defer를 호출합니다.
defer가 실행된 후에 에러 메세지가 출력이 됩니다.
package main
import "fmt"
func main() {
defer fmt.Println("Defer in main")
panic("Panic with Defer")
fmt.Println("After painc in f2")
}
Defer in main
panic: Panic with Defer
goroutine 1 [running]:
main.main()
/tmp/sandbox2806734434/prog.go:7 +0x73
Program exited.