0Pricing
Go Academy · 강의

사용자 지정 오류 만들기

errors.New, fmt.Errorf 및 센티널 오류

사용자 지정 오류 만들기은(는) CoddyKit의 무료 Go Academy 강의입니다. 이것은 4개 중 2번째 강의입니다. 아래에서 전체 강의를 무료로 읽을 수 있으며, 내장 코드 에디터와 24/7 AI 튜터와 함께 브라우저에서 직접 실습할 수 있습니다. 이 강의는 Go Academy 학습 경로의 일부이며, 진행 상황이 웹과 CoddyKit 앱에 동기화됩니다. Go Academy 강의에는 총 4개의 강의가 포함되어 있습니다.

사용자 지정 오류 타입이 필요한 이유

사용자 지정 오류 타입은 문자열 메시지를 넘어 구조화된 데이터를 전달하므로, 호출자가 특정 오류 상태를 검사하고 그에 따라 대응할 수 있습니다:

package main
import "fmt"

// Custom error type carries extra context
type HTTPError struct {
    StatusCode int
    Message    string
}

func (e *HTTPError) Error() string {
    return fmt.Sprintf("HTTP %d: %s", e.StatusCode, e.Message)
}

func fetch(url string) error {
    return &HTTPError{404, "page not found"}
}

func main() {
    err := fetch("http://example.com")
    fmt.Println(err) // HTTP 404: page not found
}

error 인터페이스 구현

Error() string 메서드를 가진 모든 타입은 error를 충족합니다:

package main
import "fmt"

type ValidationError struct {
    Field   string
    Value   interface{}
    Message string
}

func (e *ValidationError) Error() string {
    return fmt.Sprintf("validation: field %q value %v — %s", e.Field, e.Value, e.Message)
}

func validateAge(age int) error {
    if age < 0 || age > 150 {
        return &ValidationError{"age", age, "must be between 0 and 150"}
    }
    return nil
}

func main() {
    fmt.Println(validateAge(-5))
}

errors.New를 사용한 센티널 오류

센티널 오류는 잘 알려진 오류 상태를 나타내는 패키지 수준 변수입니다:

package main
import ("fmt"; "errors")

var (
    ErrNotFound      = errors.New("not found")
    ErrUnauthorized  = errors.New("unauthorized")
    ErrAlreadyExists = errors.New("already exists")
)

func getUser(id int) (string, error) {
    if id != 1 { return "", ErrNotFound }
    return "Alice", nil
}

func main() {
    _, err := getUser(99)
    if errors.Is(err, ErrNotFound) {
        fmt.Println("user does not exist")
    }
}

래핑을 위한 %w를 사용한 fmt.Errorf

%w와 함께 사용하는 fmt.Errorf는 오류를 래핑하면서 원래 오류를 보존하므로 errors.Is와 errors.As에서 사용할 수 있습니다:

package main
import ("fmt"; "errors")

var ErrDatabase = errors.New("database error")

func queryDB() error {
    return fmt.Errorf("queryDB: %w", ErrDatabase)
}

func main() {
    err := queryDB()
    fmt.Println(err)                       // queryDB: database error
    fmt.Println(errors.Is(err, ErrDatabase)) // true — unwrapped
}

Unwrap을 사용한 사용자 지정 오류

사용자 지정 오류 타입에 Unwrap() error를 구현하면 오류 체인에 참여할 수 있습니다:

package main
import ("fmt"; "errors")

var ErrNotFound = errors.New("not found")

type QueryError struct {
    Query string
    Err   error
}

func (e *QueryError) Error() string {
    return fmt.Sprintf("query %q: %v", e.Query, e.Err)
}
func (e *QueryError) Unwrap() error { return e.Err }

func main() {
    err := &QueryError{"SELECT *", ErrNotFound}
    fmt.Println(err)
    fmt.Println(errors.Is(err, ErrNotFound)) // true
}

errors.Is — 동일성 확인

errors.Is는 대상과 같은 오류를 찾을 때까지 오류 체인을 탐색합니다:

package main
import ("fmt"; "errors")

var ErrTimeout = errors.New("timeout")

func deepCall() error {
    return fmt.Errorf("layer3: %w", fmt.Errorf("layer2: %w", ErrTimeout))
}

func main() {
    err := deepCall()
    fmt.Println(errors.Is(err, ErrTimeout)) // true — found deep in chain
}

errors.As — 타입 추출

errors.As는 대상 타입과 일치하는 체인의 첫 번째 오류를 찾아 할당합니다:

package main
import ("fmt"; "errors")

type PermissionError struct{ User string }
func (e *PermissionError) Error() string { return "permission denied for " + e.User }

func action(user string) error {
    return fmt.Errorf("action: %w", &PermissionError{user})
}

func main() {
    err := action("bob")
    var pe *PermissionError
    if errors.As(err, &pe) {
        fmt.Println("denied:", pe.User) // denied: bob
    }
}

여러 오류 래핑(Go 1.20 이상)

Go 1.20에서는 오류를 결합하기 위한 errors.Join과 여러 %w를 지원하는 fmt.Errorf가 추가되었습니다:

package main
import ("fmt"; "errors")

func validate(name, email string) error {
    var errs []error
    if name == ""  { errs = append(errs, errors.New("name required")) }
    if email == "" { errs = append(errs, errors.New("email required")) }
    return errors.Join(errs...)
}

func main() {
    err := validate("", "")
    fmt.Println(err)
    // name required
    // email required
}

오류 타입 명명 규칙

Go에서 오류 변수와 타입을 명명하는 규칙은 다음과 같습니다:

  • 센티널 오류 변수: ErrXxx(예: ErrNotFound)
  • 사용자 지정 오류 타입: XxxError(예: ValidationError)
  • 센티널에는 패키지 수준 var를, 풍부한 오류에는 포인터 타입을 사용합니다
  • 호출자가 errors.Is 또는 errors.As에서 사용할 수 있도록 내보냅니다

각 접근 방식을 사용하는 경우

적절한 오류 접근 방식 선택:

  • errors.New — 추가 데이터가 없는 단순 오류 및 센티널 동일성 확인
  • fmt.Errorf — 선택적 래핑이 가능한 형식 지정 메시지
  • 사용자 지정 타입 — 호출자에게 구조화된 데이터(필드, 코드)가 필요할 때
  • errors.Join — 여러 유효성 검사 오류를 집계할 때

빠른 확인

오류 체인에서 특정 오류 타입을 추출할 수 있는 함수는 무엇인가요?

복습: 사용자 지정 오류

요약:

  • Error() string을 구현하여 사용자 지정 오류 타입을 만듭니다
  • Unwrap() error를 추가하여 오류 체인에 참여시킵니다
  • 동일성 확인에는 errors.Is를, 타입 추출에는 errors.As를 사용합니다
  • 센티널 오류: ErrXxx, 사용자 지정 타입: XxxError
  • errors.Join은 여러 오류를 집계합니다(Go 1.20 이상)

자주 묻는 질문

“사용자 지정 오류 만들기” 강의는 무료인가요?

네 — “사용자 지정 오류 만들기” 전체 내용을 이 웹사이트에서 무료로 읽을 수 있습니다. 인터랙티브하게 실습하려면(내장 코드 에디터와 24/7 AI 튜터), CoddyKit PRO로 업그레이드하면 Go Academy 강의 전체를 잠금 해제할 수 있습니다. Go Academy 강의에는 총 4개의 강의가 포함되어 있습니다.

“사용자 지정 오류 만들기”에서 뭘 배우나요?

errors.New, fmt.Errorf 및 센티널 오류 브라우저에서 직접 실행하는 실습 코드로 Go Academy을(를) 배우며, 24/7 AI 튜터가 강의를 진행하면서 질문에 답변해줍니다.

Go Academy을(를) 시작하는 데 경험이 필요한가요?

사전 경험은 필요하지 않습니다. CoddyKit의 Go Academy은(는) 초급자부터 고급 학습자까지를 위해 구성되어 있으므로, 여기서 시작하거나 처음부터 시작할 수 있으며 자신의 속도대로 진행할 수 있습니다. 이것은 4개 중 2번째 강의입니다.

“사용자 지정 오류 만들기” 강의는 얼마나 걸리나요?

대부분의 CoddyKit 강의는 약 5~10분이 소요됩니다. 각 강의는 간결하고 인터랙티브하여 꾸준한 진행이 가능하며, 웹과 앱에서 중단한 부분부터 바로 시작할 수 있습니다.

이 Go Academy 강의에서 코드를 작성하고 실행할 수 있나요?

네. 모든 Go Academy 강의에는 내장 코드 에디터가 포함되어 있으므로, 브라우저에서 바로 실제 코드를 작성하고 실행한 후 즉시 AI 피드백을 받을 수 있습니다 — 로컬 설정이 필요 없습니다.

이 강의의 모든 강의

  1. error 인터페이스
  2. 사용자 지정 오류 만들기
  3. 오류 래핑과 언래핑
  4. panic, recover 및 defer
← Go Academy(으)로 돌아가기