오류 래핑과 언래핑
%w, errors.Is 및 errors.As 사용
오류 래핑과 언래핑은(는) CoddyKit의 무료 Go Academy 강의입니다. 이것은 4개 중 3번째 강의입니다. 아래에서 전체 강의를 무료로 읽을 수 있으며, 내장 코드 에디터와 24/7 AI 튜터와 함께 브라우저에서 직접 실습할 수 있습니다. 이 강의는 Go Academy 학습 경로의 일부이며, 진행 상황이 웹과 CoddyKit 앱에 동기화됩니다. Go Academy 강의에는 총 4개의 강의가 포함되어 있습니다.
오류 래핑이란 무엇인가요
오류 래핑은 새 오류 안에 원래 오류를 포함하는 방식입니다. 원래 오류를 프로그램에서 검사할 수 있도록 보존하면서 컨텍스트를 추가합니다. Go 1.13에서 정식으로 도입되었습니다:
package main
import ("fmt"; "errors")
var ErrDB = errors.New("database unreachable")
func queryUsers() error {
return fmt.Errorf("queryUsers: %w", ErrDB)
}
func loadProfile(id int) error {
return fmt.Errorf("loadProfile(%d): %w", id, queryUsers())
}
func main() {
err := loadProfile(42)
fmt.Println(err) // loadProfile(42): queryUsers: database unreachable
}%w 동사
오류를 래핑하려면 fmt.Errorf에서 %v가 아닌 %w를 사용하세요. 래핑된 오류에는 errors.Unwrap으로 접근할 수 있습니다:
package main
import ("fmt"; "errors")
func main() {
inner := errors.New("inner error")
outer := fmt.Errorf("outer: %w", inner)
fmt.Println(outer) // outer: inner error
fmt.Println(errors.Unwrap(outer)) // inner error
fmt.Println(errors.Is(outer, inner)) // true
}errors.Unwrap
errors.Unwrap은 체인의 다음 오류(래핑된 오류)를 반환하며, 다음 오류가 없으면 nil을 반환합니다:
package main
import ("fmt"; "errors")
type Layer struct{ msg string; err error }
func (l *Layer) Error() string { return l.msg }
func (l *Layer) Unwrap() error { return l.err }
func main() {
root := errors.New("root")
mid := &Layer{"mid", root}
top := &Layer{"top", mid}
fmt.Println(errors.Unwrap(top)) // mid
fmt.Println(errors.Unwrap(mid)) // root
fmt.Println(errors.Unwrap(root)) // <nil>
}errors.Is — 체인 탐색
errors.Is(err, target)는 일치하는 오류를 찾거나 nil에 도달할 때까지 오류 체인을 재귀적으로 언래핑합니다:
package main
import ("fmt"; "errors")
var ErrNotFound = errors.New("not found")
func findItem(id int) error {
return fmt.Errorf("findItem(%d): %w",
id, fmt.Errorf("repo: %w", ErrNotFound))
}
func main() {
err := findItem(7)
fmt.Println(errors.Is(err, ErrNotFound)) // true — deep in chain
fmt.Println(err) // full message chain
}errors.As — 타입을 위한 체인 탐색
errors.As(err, &target)는 target의 타입에 할당할 수 있는 오류를 찾으며 체인을 탐색합니다:
package main
import ("fmt"; "errors")
type StatusError struct{ Code int }
func (e *StatusError) Error() string { return fmt.Sprintf("status %d", e.Code) }
func doRequest() error {
return fmt.Errorf("request: %w", &StatusError{503})
}
func main() {
err := doRequest()
var se *StatusError
if errors.As(err, &se) {
fmt.Println("status code:", se.Code) // 503
}
}체인을 위한 사용자 지정 Unwrap
사용자 지정 오류 타입에 Unwrap() error를 구현하여 errors.Is와 errors.As를 지원하세요:
package main
import ("fmt"; "errors")
type AppError struct {
Op string
Err error
}
func (e *AppError) Error() string { return fmt.Sprintf("%s: %v", e.Op, e.Err) }
func (e *AppError) Unwrap() error { return e.Err }
var ErrAuth = errors.New("unauthorized")
func main() {
err := &AppError{"login", ErrAuth}
fmt.Println(errors.Is(err, ErrAuth)) // true
}fmt.Errorf에서의 %v와 %w 비교
%v와 %w의 차이는 다음과 같습니다:
package main
import ("fmt"; "errors")
func main() {
inner := errors.New("inner")
withV := fmt.Errorf("outer: %v", inner) // string only, no wrap
withW := fmt.Errorf("outer: %w", inner) // wraps inner
fmt.Println(errors.Is(withV, inner)) // false — not wrapped
fmt.Println(errors.Is(withW, inner)) // true — wrapped
}실전 래핑: HTTP 핸들러
일관된 오류 래핑은 운영 시스템에서 디버깅을 더 쉽게 만듭니다:
package main
import "fmt"
func dbQuery(sql string) error {
return fmt.Errorf("db.Query(%q): connection refused", sql)
}
func getUserByID(id int) (string, error) {
if err := dbQuery("SELECT * FROM users WHERE id=?"); err != nil {
return "", fmt.Errorf("getUserByID(%d): %w", id, err)
}
return "Alice", nil
}
func handler() error {
_, err := getUserByID(1)
if err != nil {
return fmt.Errorf("handler: %w", err)
}
return nil
}
func main() { fmt.Println(handler()) }errors.Join — 여러 오류 래핑(Go 1.20 이상)
errors.Join은 여러 오류를 래핑하는 오류를 만듭니다. errors.Is는 모든 오류를 확인합니다:
package main
import ("fmt"; "errors")
var ErrA = errors.New("err A")
var ErrB = errors.New("err B")
func main() {
joined := errors.Join(ErrA, ErrB)
fmt.Println(joined)
fmt.Println(errors.Is(joined, ErrA)) // true
fmt.Println(errors.Is(joined, ErrB)) // true
}언래핑 모범 사례
오류 래핑 지침:
- 프로그램에서 검사할 수 있도록 오류를 보존하려면
%w로 래핑하세요 - 컨텍스트를 위해 작업 이름을 추가하세요:
fmt.Errorf("funcName: %w", err) - 호출자가
errors.Is를 사용하지 않는다면 센티널 오류를 래핑하지 마세요 - 모든 수준에서 같은 컨텍스트를 이중으로 래핑하지 마세요
- 체인에 참여하도록 사용자 지정 타입에
Unwrap()을 구현하세요
빠른 확인
fmt.Errorf에서 %v와 %w를 사용하는 것의 차이는 무엇인가요?
복습: 오류 래핑과 언래핑
요약:
fmt.Errorf("ctx: %w", err)는 컨텍스트와 함께 오류를 래핑합니다errors.Unwrap은 체인의 다음 오류를 가져옵니다errors.Is는 동일한 오류를 찾기 위해 체인을 탐색합니다errors.As는 일치하는 타입을 찾기 위해 체인을 탐색합니다- 사용자 지정 타입은
Unwrap() error를 구현합니다 errors.Join은 여러 오류를 래핑합니다(Go 1.20 이상)
자주 묻는 질문
“오류 래핑과 언래핑” 강의는 무료인가요?
네 — “오류 래핑과 언래핑” 전체 내용을 이 웹사이트에서 무료로 읽을 수 있습니다. 인터랙티브하게 실습하려면(내장 코드 에디터와 24/7 AI 튜터), CoddyKit PRO로 업그레이드하면 Go Academy 강의 전체를 잠금 해제할 수 있습니다. Go Academy 강의에는 총 4개의 강의가 포함되어 있습니다.
“오류 래핑과 언래핑”에서 뭘 배우나요?
%w, errors.Is 및 errors.As 사용 브라우저에서 직접 실행하는 실습 코드로 Go Academy을(를) 배우며, 24/7 AI 튜터가 강의를 진행하면서 질문에 답변해줍니다.
Go Academy을(를) 시작하는 데 경험이 필요한가요?
사전 경험은 필요하지 않습니다. CoddyKit의 Go Academy은(는) 초급자부터 고급 학습자까지를 위해 구성되어 있으므로, 여기서 시작하거나 처음부터 시작할 수 있으며 자신의 속도대로 진행할 수 있습니다. 이것은 4개 중 3번째 강의입니다.
“오류 래핑과 언래핑” 강의는 얼마나 걸리나요?
대부분의 CoddyKit 강의는 약 5~10분이 소요됩니다. 각 강의는 간결하고 인터랙티브하여 꾸준한 진행이 가능하며, 웹과 앱에서 중단한 부분부터 바로 시작할 수 있습니다.
이 Go Academy 강의에서 코드를 작성하고 실행할 수 있나요?
네. 모든 Go Academy 강의에는 내장 코드 에디터가 포함되어 있으므로, 브라우저에서 바로 실제 코드를 작성하고 실행한 후 즉시 AI 피드백을 받을 수 있습니다 — 로컬 설정이 필요 없습니다.