Trung BìnhGolang iconGolang

errors.Is vs errors.As khác nhau thế nào?

Cả hai dùng để kiểm tra error chain (chuỗi lỗi được wrap), nhưng mục đích khác nhau.

errors.Is(err, target) — kiểm tra identity: err có phải (hoặc wrap) target không? Dùng cho sentinel errors (lỗi được định nghĩa sẵn).

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

// Wrap lỗi qua nhiều layers
err := fmt.Errorf("service: %w", fmt.Errorf("repo: %w", ErrNotFound))

errors.Is(err, ErrNotFound) // true — dù wrap 2 lần
errors.Is(err, ErrNotFound) // false nếu dùng %v thay vì %w

errors.As(err, &target) — kiểm tra type: err có phải (hoặc wrap) một lỗi thuộc kiểu cụ thể không? Dùng cho custom error types để truy xuất thêm thông tin.

go
type ValidationError struct {
    Field   string
    Message string
}
func (e *ValidationError) Error() string {
    return fmt.Sprintf("validation: %s — %s", e.Field, e.Message)
}

err := fmt.Errorf("handler: %w", &ValidationError{Field: "email", Message: "invalid"})

var ve *ValidationError
if errors.As(err, &ve) {
    fmt.Println(ve.Field)   // "email"
    fmt.Println(ve.Message) // "invalid"
}

Tóm tắt: errors.Is so sánh giá trị, errors.As so sánh kiểu.

Luôn dùng %w khi wrap để giữ chain.

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

Mở danh sách Golang