문제의 역사:
defer, panic 및 recover 연산자는 Go의 실행 흐름 관리에서 중요한 메커니즘입니다. defer 연산자는 함수의 지연 실행을 위해 사용되고, panic은 오류(비상 종료)를 발생시키며, recover는 비상 사태를 포착하고 실행을 계속할 수 있게 해줍니다.
문제:
이 도구들을 적절히 사용하지 않으면 자원을 올바르게 정리하고 내결함성을 구현하기가 어렵습니다. 함수의 예측할 수 없는 종료, 해제되지 않은 자원 및 오류 발생 시 애플리케이션이 제어되지 않고 "탈출"하는 것이 잘못된 접근 방식에서 발생하는 빈번한 문제입니다.
해결책:
defer의 올바른 사용은 오류 발생 시에도 안전하게 자원을 해제할 수 있도록 보장합니다. panic은 비정상적인 상황에서의 비상 종료 메커니즘으로, 정말 예외적인 경우에만 사용해야 합니다. recover는 지연된 함수 내에서 실행을 "구할" 수 있는 기회를 제공합니다.
코드 예:
func riskyFunction() { defer func() { if r := recover(); r != nil { fmt.Println("Recovered in riskyFunction:", r) } }() fmt.Println("Doing some work...") panic("something bad happened!") } func main() { riskyFunction() fmt.Println("After riskyFunction") }
주요 특징:
defer는 항상 함수에서 나가기 전에 반대 순서로 호출됩니다. panic이 발생해도 마찬가지입니다.recover는 오직 지연된 함수 내에서만 작동합니다.panic은 현재 고루틴의 실행을 중단시키며, 만약 recover에 의해 포착되지 않으면 프로세스를 종료시킵니다.왜 recover가 같은 함수 내의 defer 외부에서 호출되어도 작동하지 않습니까?
recover는 panic이 발생한 함수 내의 defer 함수에서 호출될 때만 널이 아닌 값을 반환(즉, 패닉을 포착)합니다. 만약 recover를 직접 호출하면 항상 nil을 반환합니다.
코드 예:
func f() { panic("fail!") r := recover() // 작동하지 않음! }
panic 이후에 defer를 호출할 수 있습니까, 그렇다면 실행됩니까?
아니요. panic 이후에는 이미 등록된 모든 defer 호출이 실행되지만, panic 이후에 새로운 defer는 호출되지 않습니다, 왜냐하면 함수의 실행이 이미 "축소"되기 때문입니다.
다른 고루틴에서 발생한 panic에서 recover할 수 있습니까?
아니요, recover는 현재 고루틴의 panic에 대해서만 작동합니다. 만약 다른 고루틴에서 panic이 발생하고 그 고루틴 내에서 recover가 호출되지 않으면 애플리케이션은 종료됩니다.
프로젝트에서 모든 오류가 panic을 통해 발생되었고, recovery 처리는 오직 메인 함수에서만 이루어졌습니다. 이로 인해 자원이 닫히지 않고, 일부 데이터가 손실되며, 로그가 해독하기 어려운 상태가 되었습니다.
장점:
단점:
각 중요 부분에서 자원을 해제하기 위해 defer가 사용되었으며, panic은 오직 진정으로 예외적인 상황에서만 사용되고, recover는 비판적인 부분에서의 비상 상황을 격리하는 데 사용되었습니다. 이와 함께 모든 오류 세부 사항이 로그에 기록되었습니다.
장점:
단점: