질문 배경:
Go 1.13 이전에는 오류가 단순한 인터페이스였습니다. 오류에 대한 추가적인 컨텍스트를 제공하기 위해 종종 사용자 정의 유형을 만들었지만, modern Java 또는 C#에서와 같은 구조화된 중첩 메커니즘은 존재하지 않았습니다. Go 1.13에서는 fmt.Errorf 함수를 통한 오류 wrapping의 표준 방법과 근본 원인을 식별하는 방법(errors.Is/errors.As)이 도입되었습니다.
문제:
오류가 스택의 여러 계층에서 발생할 수 있는 복잡한 애플리케이션에서는 오류를 코드 깊숙한 곳에서 반환할 때 컨텍스트를 잃지 않는 것이 중요합니다. 그렇지 않으면 디버깅이 어려워지고 체인 내에서 실패가 발생한 위치를 이해할 수 없게 됩니다.
해결 방법:
Go는 원인을 포함하는 새로운 오류 객체에 오류를 감싸는 것을 제안합니다. 이를 위해 fmt.Errorf의 %w를 사용하고, 심층적 원인을 확인하기 위해 errors.Is 또는 errors.As를 errors 패키지에서 사용합니다.
코드 예제:
import ( "errors" "fmt" ) var ErrNotFound = errors.New("not found") func getData() error { return fmt.Errorf("service database: %w", ErrNotFound) } func main() { err := getData() if errors.Is(err, ErrNotFound) { fmt.Println("원인 발견: 찾을 수 없음") } else { fmt.Println("다른 오류:", err) } }
주요 특징:
fmt.Errorf를 통해 오류를 중첩할 때 %w 사용.errors.Is 및 errors.As를 통한 중첩 오류 원인 식별.fmt.Errorf를 사용한 오류 wrapping에 사용해야 하는 포맷팅 연산자는 무엇인가요?
정확히 %w를 사용해야 하며, %v를 사용하면 안 됩니다 — %w만이 unwrapping 지원을 제공합니다.
코드 예제:
fmt.Errorf("오류: %w", err)
fmt.Errorf 없이 수동으로 오류 체인을 만들고 여전히 errors.Is를 통해 식별할 수 있나요?
아니요, Unwrap 인터페이스를 구현해야 합니다. 그렇지 않으면 표준 함수들이 체인을 펼칠 수 없습니다.
인터페이스 코드 예제:
type wrappedError struct { msg string err error } func (w wrappedError) Error() string { return w.msg + ": " + w.err.Error() } func (w wrappedError) Unwrap() error { return w.err }
중첩된 오류가 nil이면 wrapping 후 오류가 nil인가요?
아니요, 중첩 오류가 nil인 경우, 적절히 사용하면 wrapping된 오류도 nil입니다. 하지만 오류 필드가 nil인 래퍼 구조체를 수동으로 만들면 nil이 아니게 됩니다. 이는 확인할 때 혼란을 자주 초래합니다.
%w가 아니라 %v 사용 — 체인 분석의 가능성을 잃게 됩니다.Unwrap()을 구현하지 않음.errors.Is/As를 사용하지 않고 오류를 직접 비교함.애플리케이션에서 각 레벨마다 텍스트로 새로운 오류를 단순히 반환했습니다:
return errors.New("데이터베이스에 쓰기 오류")
장점:
단점:
%w로 오류를 wrapping하고 errors.Is를 통해 분석한 경우:
if errors.Is(err, ErrNotFound) { return fmt.Errorf("서비스 레벨의 오류: %w", err) }
장점:
단점: