- go의 Error는 Error()를 들고있는 인터페이스다.
- Exception처리가 없어서 매우 짜증난다.
에러 처리의 종류
Sentinel Error
1 |
|
- 에러의 종류에 따라 Control Flow가 바뀜
- 안좋다. 패키지간 의존성이 생긴다. 쓰지말자.
Error Type
1 |
|
- 에러에 추가정보를 넣기 위해서 타입을 만드는 경우
- 에러 타입을 정의한 패키지와 모든 패키지가 큰 의존성을 갖게 됨.
- 사용을 피하자.
Opaque Error
- 에러의 내용을 검사하지 말고 그저 리턴하기
- 만약 외부 동작에 의해서, 에러의 내용을 검사하는게 불가피하다면,
- type assertion을 이용해서 interface로 변환가능한지 살펴보기
- 즉 Error에 대해서 어떤 행위가 가능한지 살펴보기.
- 이 방식으로 구현하면 error를 정의한 패키지를 임포트 할 필요가 없다.
- 결론은 이렇게 단순하게 에러만 리턴하자.
더 나은 에러 처리를 위한 조언들
Error에 내용을 덧붙이기
- fmt 패키지의
Errorf
를 쓰면 error를 포매팅해서 덧붙일 수 있다. - 근데
return fmt.Errorf("decompress %v: %v", name, err)
이렇게 쓰면 원래의 err 타입이 날아가버린다.- Wrapping 한 에러가 ErrNotFound 였더라도 비교해서 검사할 수 없다. (불가피한 경우에도)
- 그래서
%w
로 포매팅하자.- 그러면
if errors.Is(err, sql.ErrNoRows)
로 검사할 수 있다.
- 그러면
에러의 종류 검사하기
- 예전에는 TypeAssertion을 썼지만, 이건 타입을 %v로 뭉개버렸으면 소용없다.
- 1.13부터는 errors.As를 쓰면 손쉽다. 여러번 Wrap되어있어도 다 까본다고 한다.
강력한 pkg/errors
- 외부 pkg인 errors를 쓰면 그냥 스택까지 쫙 찍어준다.
- 요걸 써보길 추천. errors가 리턴해주는 에러도 여전히 에러기 때문에 Is나 As랑도 잘 맞는다.