Error
- 다른 언어들과 달리, Go에는 오류를 검출하는
Exception
과 같은 특별한 구문이 없다.
- 함수가 반환할 때마다 if문을 사용하여 오류 변수가
nil
이 아닌지 확인한다.
error
는 단일 메서드를 정의하는 내장 인터페이스이다.
type error interface {
Error() string
}
- 문자열로 오류를 생성하는 두 가지 방법
errors.New(string)
fmt.Errorf(string, format)
- fmt.Printf의 모든 format 동사를 사용할 수 있다.
- 센티넬 오류
- 특정 값을 사용하여 오류를 나타내는 것
- ex -
rsa.ErrMessageTooLong
오류는 값이다.
- 로깅, 오류 처리를 위한 추가적 정보를 포함하여 자신만의 오류를 정의할 수 있다.
- 열거형을 통해 상태 코드를 직접 정의할 수 있다.
type MdlCode int
const (
CodeCommAuthenticationFailed MdlCode = 10
CodeCommAccessTokenExpired MdlCode = 20
...
)
error
인터페이스 충족을 위해Error() string
를 구현한다.
type commonError struct {
error error
statusCode int
mdlCode MdlCode
message string
reasons []string
}
func (c *commonError) Error() string {
var message string
if c.error != nil {
message = message + c.error.Error()
}
message = message + fmt.Sprintf(", errorCode: %d", c.mdlCode)
if c.getReasons() != "" {
message = message + fmt.Sprintf(" [reasons:%s]", c.getReasons())
}
return message
}
오류 래핑
- 오류 래핑
-
errors.Wrap(err, message)
fmt.Errorf(str)
-%w
를 통해 래핑 가능- 호출 스택 추가
- 기존 에러를 받아 새로운 에러를 생성하고 추가 정보를 포함
errors.Unwrap(wrappedErr)
- 래핑된 에러의 원래 에러를 추출
import "github.com/pkg/errors"
func foo() error {
return errors.Wrap(sql.ErrNoRows, "foo failed") // attach the call stack
// return errors.WithStack(sql.ErrNoRows) // attach the call stack without message
}
func bar() error {
return errors.WithMessage(foo(), "bar failed") // without attaching call stack
}
func main() {
err := bar()
if errors.Cause(err) == sql.ErrNoRows {
fmt.Printf("data not found, %v\n", err)
fmt.Printf("%+v\n", err)
return
}
}
/*Output:
data not found, bar failed: foo failed: sql: no rows in result set
sql: no rows in result set
foo failed
main.foo
/usr/three/main.go:11
main.bar
/usr/three/main.go:15
main.main
/usr/three/main.go:19
runtime.main
...
*/
Is와 As
- 센티넬 오류 래핑 시 확인을 위해
==
를 사용할 수 없으며, 이를 해결하기 위해 erros의Is, As
를 사용한다.
erros.Is
- 반환된 오류나 래핑된 오류를 센티넬 오류 인스턴스와 일치하는지 확인
- 확인할 오류, 오류의 인스턴스를 파라미터로 받는다.
if errors.Is(err, os.ErrNotExist) {
fmt.Println("That file doesn't exist)
}
errors.As
- 반환된 오류가 특정 타입과 일치하는지 확인
- 검사할 오류, 찾고자 하는 타입의 변수를 가르키는 포인터를 파라미터로 받는다.
if errors.As(err, &myErr) {
fmt.Println(myErr.Code)
}
defer로 오류 매핑
- 같은 메세지로 여러 오류를 매핑한 경우 defer로 한번에 처리할 수 있다.
- 함수 반환 값에 이름을 부여했다. defer에서 err을 참조할 수 있게 하기 위해서다.
- 에러 발생 시 defer에서 err을 재할당해준다.
func DoSomeThing(val1 int, val2 string) (_ string, err error){
defer func() {
if err != nil {
err = fmt.Errorf("in DoSomeThings: %w", err)
}
}()
val3 ,err = doThing1(val1)
if err != nil {
return "", err
}
val3 ,err = doThing1(val2)
if err != nil {
return "", err
}
return doThing3(val3, val4)
}
Panic, recover
panic
- 프로그래밍 오류나 메모리 부족과 같은 이유로 패닉이 되면, 현재 함수는 즉시 종료되고 함수에 연결된 모든 defer 함수가 실행을 시작한다.
- 프로그램이 복구할 수 없는 상황이라면, 직접 패닉을 생성할 수 있다.
panic(string)
- 문자열 파라미터를 받는다.
recover
- panic시 안정적인 종료를 제공하거나 종료 방지, 패닉을 확인하기 위해 사용
- defer 내부에서 호출해야 한다
Share article