Panic, Defer, Recover
Coddy GO 여정의 객체 지향 프로그래밍 섹션에 포함된 레슨. 107개 중 57번째.
Go는 errors 반환을 중시하지만, 일부 상황은 정말로 복구할 수 없습니다. 이러한 경우를 위해 Go는 예외적인 상황을 처리하는 메커니즘인 panic, defer, recover를 제공합니다.
panic은 정상적인 실행을 즉시 중단합니다. 이는 범위를 벗어난 인덱스에 액세스하는 것과 같은 프로그래밍 오류를 위한 것이며, 잘못된 사용자 입력과 같은 예상 가능한 오류를 위한 것이 아닙니다.
func MustGetConfig(key string) string {
value, exists := config[key]
if !exists {
panic("missing required config: " + key)
}
return value
}defer는 주변 function이 정상적으로 반환되거나 panic으로 인해 반환될 때 function을 실행하도록 예약합니다. deferred calls는 역순(마지막 입력, 첫 번째 출력)으로 execute됩니다:
func ProcessFile() {
fmt.Println("Opening file")
defer fmt.Println("Closing file")
fmt.Println("Processing...")
// 출력: Opening file, Processing..., Closing file
}recover는 패닉을 포착하고 정상적인 실행을 재개합니다. 이는 deferred 함수 내부에서만 작동합니다:
func SafeOperation() (err error) {
defer func() {
if r := recover(); r != nil {
err = fmt.Errorf("recovered from panic: %v", r)
}
}()
riskyOperation()
return nil
}이 패턴은 panic을 일반적인 error로 변환하여 프로그램이 계속 실행될 수 있도록 합니다. 신중하게 사용하세요. 예상되는 실패 상황에서는 error를 반환하는 것을 우선하고, 상태가 손상되었거나 복구할 수 없는 조건과 같은 정말 예외적인 상황에만 panic/recover를 사용하세요.
챌린지
쉬움panic, defer, recover를 사용하여 예외적인 상황을 우아하게 처리하는 방법을 보여 주는 안전한 division 계산기를 만들어 봅시다. 계산기는 위험할 수 있는 연산을 시도하고, panic을 정상적으로 처리할 수 있는 일반적인 error로 convert합니다.
코드를 두 개의 파일로 구성합니다.
calculator.go: panic 복구 기능을 포함한 division 로직을 create합니다.두 개의 integer를 인수로 받고 divisor가 0이면
"division by zero"message와 함께 panic하는Dividefunction을 구현합니다. 그렇지 않으면 division의 integer 결과를 반환합니다.두 개의 integer를 인수로 받고 integer 결과와
error를 모두 반환하는SafeDividefunction을 구현합니다. 이 function은 다음을 수행해야 합니다.- 익명 function과 함께
defer를 사용하여 모든 panic을 recover합니다. - panic이 recover되면
"calculation error: [panic message]"format으로 error로 convert합니다. - 내부에서
Dividefunction을 Call합니다. - 성공하면 결과와
nil을 반환하고, panic이 recover되면 0과 error를 반환합니다.
- 익명 function과 함께
main.go: input에서 두 개의 integer를 Read하고SafeDivide를 사용하여 calculation을 안전하게 수행합니다. 또한 올바른 order로 cleanup message를 Print하여defer를 보여 줍니다.main function은 다음을 수행해야 합니다.
- 처음에
Starting calculation을 Print합니다. defer를 사용하여Cleanup complete를 Print하도록 예약합니다.- 또 다른
defer를 사용하여Releasing resources를 Print하도록 예약합니다. - input values와 함께
SafeDivide를 Call합니다. - 결과에 따라
Result: [value]또는Error: [error message]를 Print합니다.
- 처음에
다음 input이 제공됩니다.
- Line 1: 첫 번째 integer (dividend)
- Line 2: 두 번째 integer (divisor)
deferred calls는 reverse order(last-in, first-out)로 execute되므로 cleanup message는 defer된 순서의 반대 순서로 나타나야 한다는 점을 기억하세요.
예를 들어 20과 4가 주어지면 output은 다음과 같아야 합니다.
Starting calculation
Result: 5
Releasing resources
Cleanup complete그리고 10과 0이 주어지면 output은 다음과 같아야 합니다.
Starting calculation
Error: calculation error: division by zero
Releasing resources
Cleanup complete직접 해보기
package main
import (
"fmt"
)
func main() {
// 입력 읽기
var dividend, divisor int
fmt.Scanln(÷nd)
fmt.Scanln(&divisor)
// 시작 메시지 출력
fmt.Println("Starting calculation")
// TODO: Use defer to schedule "Cleanup complete" message
// TODO: Use defer to schedule "Releasing resources" message
// 기억하세요: deferred 호출은 LIFO 순서(last-in, first-out)로 실행됩니다
// TODO: 입력 값으로 SafeDivide 호출
// TODO: "Result: [value]" 또는 "Error: [error message]"를 출력
// 오류가 반환되었는지 여부에 따라
}
이 레슨에는 짧은 퀴즈가 포함되어 있습니다. 레슨을 시작해 문제를 풀고 진행 상황을 기록하세요.
객체 지향 프로그래밍의 모든 레슨
8에러 처리와 OOP
error 인터페이스사용자 정의 에러 타입에러 래핑 (fmt.Errorf)센티넬 에러errors.Is()와 errors.As()Panic, Defer, Recover요약 - 파일 파서직접 연습해 보세요: 온라인 Go 컴파일러