0Pricing
Go Academy · 강의

panic, recover 및 defer

언제 panic을 사용하고 어떻게 우아하게 복구할지 학습합니다.

panic, recover 및 defer은(는) CoddyKit의 무료 Go Academy 강의입니다. 이것은 4개 중 4번째 강의입니다. 아래에서 전체 강의를 무료로 읽을 수 있으며, 내장 코드 에디터와 24/7 AI 튜터와 함께 브라우저에서 직접 실습할 수 있습니다. 이 강의는 Go Academy 학습 경로의 일부이며, 진행 상황이 웹과 CoddyKit 앱에 동기화됩니다. Go Academy 강의에는 총 4개의 강의가 포함되어 있습니다.

panic이란 무엇인가요

panic은 현재 고루틴의 정상 실행을 중단하고, 지연된 함수를 실행하면서 호출 스택을 되감습니다. 복구되지 않으면 프로그램이 종료됩니다:

package main
import "fmt"

func mustPositive(n int) int {
    if n <= 0 {
        panic(fmt.Sprintf("mustPositive: got %d", n))
    }
    return n
}

func main() {
    fmt.Println(mustPositive(5))  // 5
    // fmt.Println(mustPositive(-1)) // panics!
}

panic을 사용하는 경우

다음과 같은 경우에만 panic을 사용하세요:

  • 정말로 복구할 수 없는 프로그래머 오류(불변식 위반)
  • 버그를 나타내는 불가능한 상태
  • 시작 실패(설정 누락, 초기화 중 연결 실패)

예상 가능한 실패 상태에는 절대 panic을 사용하지 말고 error를 사용하세요.

defer 기초

defer는 둘러싼 함수가 반환될 때 함수를 호출하도록 예약합니다. 정상 반환, 오류 반환, 패닉 등 반환 방식과 관계없이 실행됩니다:

package main
import "fmt"

func main() {
    defer fmt.Println("third")
    defer fmt.Println("second")  // LIFO order
    defer fmt.Println("first")
    fmt.Println("running...")
    // Output:
    // running...
    // first
    // second
    // third
}

정리를 위한 defer

defer의 가장 일반적인 용도는 리소스가 정리되도록 보장하는 것입니다:

package main
import ("fmt"; "os")

func readFile(path string) (string, error) {
    f, err := os.Open(path)
    if err != nil {
        return "", fmt.Errorf("open: %w", err)
    }
    defer f.Close()  // always runs, even if we return early

    buf := make([]byte, 1024)
    n, _ := f.Read(buf)
    return string(buf[:n]), nil
}

recover — 패닉 잡기

recover는 패닉을 중지하고 패닉 값을 반환합니다. defer 함수 내부에서 직접 호출해야 합니다:

package main
import "fmt"

func safeDiv(a, b int) (result int, err error) {
    defer func() {
        if r := recover(); r != nil {
            err = fmt.Errorf("recovered from panic: %v", r)
        }
    }()
    return a / b, nil  // panics if b==0
}

func main() {
    r, err := safeDiv(10, 0)
    fmt.Println(r, err)
    // 0 recovered from panic: runtime error: integer divide by zero
}

recover는 지연된 함수 안에 있어야 합니다

recover는 지연된 함수 내부에서 직접 호출될 때만 작동합니다. 다른 곳에서 호출하면 nil을 반환합니다:

package main
import "fmt"

func wrong() {
    // recover() here does nothing — not in defer
}

func correct() {
    defer func() {
        if r := recover(); r != nil {
            fmt.Println("caught:", r)
        }
    }()
    panic("oops")
}

func main() { correct() }

라이브러리 코드의 패닉

라이브러리 코드는 호출자에게 패닉이 전달되도록 두어서는 거의 안 됩니다. 경계에서 패닉을 오류로 변환하세요:

package main
import ("fmt"; "runtime/debug")

func safeCall(fn func()) (err error) {
    defer func() {
        if r := recover(); r != nil {
            err = fmt.Errorf("panic: %v\n%s", r, debug.Stack())
        }
    }()
    fn()
    return nil
}

func main() {
    err := safeCall(func() { panic("boom") })
    fmt.Println(err != nil) // true
}

defer의 LIFO 순서와 반복문 함정

지연된 호출은 후입선출(LIFO) 순서로 실행됩니다. 반복문 안에서 defer를 사용할 때는 주의하세요. 클로저나 도우미 함수를 사용하세요:

package main
import "fmt"

func processFiles(names []string) {
    for _, name := range names {
        name := name  // capture loop variable
        defer func() { fmt.Println("close:", name) }()
    }
}

func main() {
    processFiles([]string{"a.txt", "b.txt", "c.txt"})
    // Output (LIFO): close: c.txt, close: b.txt, close: a.txt
}

이름 있는 반환 값과 defer

지연된 함수는 이름 있는 반환 값을 읽고 수정할 수 있으므로 오류에 설명을 추가할 때 유용합니다:

package main
import "fmt"

func doWork() (err error) {
    defer func() {
        if err != nil {
            err = fmt.Errorf("doWork: %w", err)
        }
    }()
    return fmt.Errorf("something failed")
}

func main() {
    err := doWork()
    fmt.Println(err) // doWork: something failed
}

panic과 error: 선택 가이드

panic과 error 중 선택하기:

  • error 사용: 예상 가능한 실패(파일을 찾을 수 없음, 네트워크 시간 초과, 잘못된 입력)
  • panic 사용: 프로그래밍 오류(nil 맵 접근, 범위를 벗어난 접근), 불가능한 상태, 초기화 실패
  • API 경계를 넘어 panic을 사용하지 마세요. 호출자가 처리할 수 없습니다
  • 서버에서는 종료를 방지하기 위해 고루틴의 최상위 수준에서 패닉을 복구하세요

빠른 확인

패닉을 잡으려면 recover()를 어디에서 호출해야 하나요?

복습: panic, recover, defer

요약:

  • panic: 스택을 되감고 지연된 함수를 실행하며, 복구되지 않으면 프로그램이 중단됩니다
  • defer: 함수가 종료될 때(정상 종료, 오류 또는 패닉 발생 시) 실행되며 LIFO 순서를 따릅니다
  • recover: 패닉을 중지하고 값을 반환하며, 반드시 defer 안에서 사용해야 합니다
  • 예상되는 실패가 아니라 프로그래머의 오류에 panic을 사용합니다
  • API 경계에서 패닉을 오류로 변환합니다

자주 묻는 질문

“panic, recover 및 defer” 강의는 무료인가요?

네 — “panic, recover 및 defer” 전체 내용을 이 웹사이트에서 무료로 읽을 수 있습니다. 인터랙티브하게 실습하려면(내장 코드 에디터와 24/7 AI 튜터), CoddyKit PRO로 업그레이드하면 Go Academy 강의 전체를 잠금 해제할 수 있습니다. Go Academy 강의에는 총 4개의 강의가 포함되어 있습니다.

“panic, recover 및 defer”에서 뭘 배우나요?

언제 panic을 사용하고 어떻게 우아하게 복구할지 학습합니다. 브라우저에서 직접 실행하는 실습 코드로 Go Academy을(를) 배우며, 24/7 AI 튜터가 강의를 진행하면서 질문에 답변해줍니다.

Go Academy을(를) 시작하는 데 경험이 필요한가요?

사전 경험은 필요하지 않습니다. CoddyKit의 Go Academy은(는) 초급자부터 고급 학습자까지를 위해 구성되어 있으므로, 여기서 시작하거나 처음부터 시작할 수 있으며 자신의 속도대로 진행할 수 있습니다. 이것은 4개 중 4번째 강의입니다.

“panic, recover 및 defer” 강의는 얼마나 걸리나요?

대부분의 CoddyKit 강의는 약 5~10분이 소요됩니다. 각 강의는 간결하고 인터랙티브하여 꾸준한 진행이 가능하며, 웹과 앱에서 중단한 부분부터 바로 시작할 수 있습니다.

이 Go Academy 강의에서 코드를 작성하고 실행할 수 있나요?

네. 모든 Go Academy 강의에는 내장 코드 에디터가 포함되어 있으므로, 브라우저에서 바로 실제 코드를 작성하고 실행한 후 즉시 AI 피드백을 받을 수 있습니다 — 로컬 설정이 필요 없습니다.

이 강의의 모든 강의

  1. error 인터페이스
  2. 사용자 지정 오류 만들기
  3. 오류 래핑과 언래핑
  4. panic, recover 및 defer
← Go Academy(으)로 돌아가기