Error handling nâng cao
D1. Custom Error Types
type NotFoundError struct {
Resource string
ID int
}
func (e *NotFoundError) Error() string {
return fmt.Sprintf("%s ID=%d không tồn tại", e.Resource, e.ID)
}
// Dùng
return &NotFoundError{Resource: "User", ID: 42}
Sentinel errors — hằng số lỗi
var ErrNotFound = errors.New("not found")
if err == ErrNotFound { ... }
D2. errors.Is và errors.As
Sau khi wrap lỗi với %w, muốn kiểm tra lỗi gốc:
err := fmt.Errorf("query failed: %w", ErrNotFound)
// errors.Is — check "lỗi này CÓ PHẢI ErrNotFound không?"
if errors.Is(err, ErrNotFound) { ... }
// errors.As — check "lỗi này CÓ THUỘC loại *NotFoundError không?"
var nfe *NotFoundError
if errors.As(err, &nfe) {
fmt.Println("Resource:", nfe.Resource)
}
D3. panic & recover
panic — dừng chương trình
if config == nil {
panic("config bị nil, không thể chạy")
}
recover — bắt panic (chỉ dùng trong defer)
func safeRun() {
defer func() {
if r := recover(); r != nil {
fmt.Println("Đã bắt panic:", r)
}
}()
panic("boom!")
}
👉 Nguyên tắc: panic chỉ dùng cho lỗi không thể phục hồi. Đừng dùng như try/catch của Java.