Menu
Coddy logo textTech

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를 사용하세요.

challenge icon

챌린지

쉬움

panic, defer, recover를 사용하여 예외적인 상황을 우아하게 처리하는 방법을 보여 주는 안전한 division 계산기를 만들어 봅시다. 계산기는 위험할 수 있는 연산을 시도하고, panic을 정상적으로 처리할 수 있는 일반적인 error로 convert합니다.

코드를 두 개의 파일로 구성합니다.

  • calculator.go: panic 복구 기능을 포함한 division 로직을 create합니다.

    두 개의 integer를 인수로 받고 divisor가 0이면 "division by zero" message와 함께 panic하는 Divide function을 구현합니다. 그렇지 않으면 division의 integer 결과를 반환합니다.

    두 개의 integer를 인수로 받고 integer 결과와 error를 모두 반환하는 SafeDivide function을 구현합니다. 이 function은 다음을 수행해야 합니다.

    • 익명 function과 함께 defer를 사용하여 모든 panic을 recover합니다.
    • panic이 recover되면 "calculation error: [panic message]" format으로 error로 convert합니다.
    • 내부에서 Divide function을 Call합니다.
    • 성공하면 결과와 nil을 반환하고, panic이 recover되면 0과 error를 반환합니다.
  • 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된 순서의 반대 순서로 나타나야 한다는 점을 기억하세요.

예를 들어 204가 주어지면 output은 다음과 같아야 합니다.

Starting calculation
Result: 5
Releasing resources
Cleanup complete

그리고 100이 주어지면 output은 다음과 같아야 합니다.

Starting calculation
Error: calculation error: division by zero
Releasing resources
Cleanup complete
REQUIRED OUTPUT FORMAT: [Your translated content here]

직접 해보기

package main

import (
	"fmt"
)

func main() {
	// 입력 읽기
	var dividend, divisor int
	fmt.Scanln(&dividend)
	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]"를 출력
	// 오류가 반환되었는지 여부에 따라
}
quiz icon실력 점검

이 레슨에는 짧은 퀴즈가 포함되어 있습니다. 레슨을 시작해 문제를 풀고 진행 상황을 기록하세요.

객체 지향 프로그래밍의 모든 레슨

직접 연습해 보세요: 온라인 Go 컴파일러