Nâng CaoGolang iconGolang

Sentinel errors và custom error types — khi nào dùng cái nào?

Sentinel error là biến error toàn cục được định nghĩa sẵn, phù hợp cho các điều kiện lỗi đơn giản không cần thêm context. Custom error type phù hợp khi cần mang thêm metadata về lỗi.

go
// Sentinel errors — so sánh bằng errors.Is
var (
    ErrNotFound   = errors.New("not found")
    ErrUnauthorized = errors.New("unauthorized")
    ErrConflict   = errors.New("already exists")
)

// Custom error type — truy xuất metadata qua errors.As
type AppError struct {
    Code    int
    Message string
    Err     error // wrapped underlying error
}

func (e *AppError) Error() string {
    return fmt.Sprintf("[%d] %s", e.Code, e.Message)
}

func (e *AppError) Unwrap() error { return e.Err } // quan trọng cho error chain

func getUser(id int) (*User, error) {
    user, err := db.Find(id)
    if err != nil {
        return nil, &AppError{Code: 404, Message: "user not found", Err: ErrNotFound}
    }
    return user, nil
}

// Caller có thể check cả hai cách
err := getUser(99)
errors.Is(err, ErrNotFound) // true — nhờ Unwrap()
var ae *AppError
if errors.As(err, &ae) {
    fmt.Println(ae.Code) // 404
}

Nguyên tắc: định nghĩa errors trong package, export chúng để caller dùng errors.Is.

Tránh dùng err.Error() == "..." string comparison.

Xem toàn bộ Golang cùng filter theo level & chủ đề con.

Mở danh sách Golang