Go에서 패닉 잡기

Jay Singh 2023년6월20일
  1. Go에서 패닉 잡기
  2. Go의 패닉 복구
Go에서 패닉 잡기

오류와 같은 Panic은 런타임 중에 발생합니다. 즉, Go 프로그램에서 예기치 않은 상황이 발생하여 실행이 종료될 때 패닉이 발생합니다.

범위를 벗어난 어레이 액세스와 같은 특정 조건이 발생하면 런타임 중에 패닉이 발생할 수 있습니다. 이러한 일반적인 작업은 한계를 넘어 배열을 인덱싱하고, 유형 테스트를 수행하고, nil 포인터에서 메서드를 실행하고, 뮤텍스를 잘못 사용하고, 닫힌 채널과 상호 작용을 시도하는 것입니다.

이러한 시나리오의 대부분은 소프트웨어를 빌드하는 동안 컴파일러가 발견할 수 없는 프로그래밍 오류에서 발생합니다. 패닉은 문제를 해결하는 데 중요한 정보를 제공하기 때문에 개발자는 종종 패닉을 사용하여 개발 중에 실수를 저질렀음을 나타냅니다.

Golang에서 패닉을 포착하는 몇 가지 예를 살펴보겠습니다.

Go에서 패닉 잡기

아래 프로그램은 사람의 전체 이름을 인쇄합니다. fullName 기능은 사람의 전체 이름을 출력합니다.

이 메서드는 firstNamelastName 포인터가 null인지 확인합니다. nil인 경우 함수는 적절한 메시지와 함께 패닉을 호출합니다.

예 1:

package main

import (
    "fmt"
)

func fullName(firstName *string, lastName *string) {
    if firstName == nil {
        panic("runtime error: first name cannot be nil")
    }
    if lastName == nil {
        panic("runtime error: last name cannot be nil")
    }
    fmt.Printf("%s %s\n", *firstName, *lastName)
    fmt.Println("returned normally from fullName")
}

func main() {
    firstName := "Jay"
    fullName(&firstName, nil)
    fmt.Println("returned normally from main")
}

출력:

panic: runtime error: last name cannot be nil

goroutine 1 [running]:
main.fullName(0x405058?, 0xc0000a2f70?)
    /tmp/sandbox3339134150/prog.go:12 +0x114
main.main()
    /tmp/sandbox3339134150/prog.go:20 +0x35

아래 코드는 employee 함수가 main 함수에서 호출되는 것을 보여줍니다. 직원의 이름나이를 입력으로 제출합니다.

직원의 나이가 정년을 넘으면 직원 기능이 패닉 상태가 됩니다.

예 2:

package main

func employee(name *string, age int) {
    if age > 65 {
        panic("Age cannot be greater than retirement age")
    }
}
func main() {
    empName := "Jay"
    age := 73

    employee(&empName, age)
}

출력:

panic: Age cannot be greater than retirement age

goroutine 1 [running]:
main.employee(...)
    /tmp/sandbox4109873090/prog.go:5
main.main()
    /tmp/sandbox4109873090/prog.go:12 +0x27
exit status 2

Go의 패닉 복구

복구 기능은 오류 값을 사용하여 패닉이 발생했는지 여부를 결정합니다. 패닉 함수의 입력은 빈 인터페이스이므로 모든 유형이 될 수 있습니다.

빈 인터페이스를 포함한 모든 인터페이스 유형은 nil의 0 값을 가집니다. 이 예에서 볼 수 있듯이 패닉에 대한 입력으로 nil을 사용하지 않도록 주의해야 합니다.

예:

package main
import (
    "fmt"
    "log"
)
func main() {
    divideByZero()
    fmt.Println("Hey, we survived dividing by zero!")

}
func divideByZero() {
    defer func() {
        if err := recover(); err != nil {
            log.Println("panic occurred:", err)
        }
    }()
    fmt.Println(divide(1, 0))
}
func divide(a, b int) int {
    if b == 0 {
        panic(nil)
    }
    return a / b
}

출력:

Hey, we survived dividing by zero!