Is/As/Wrap, sentinel, panic/recover ใช้ให้ถูก
f, err := os.Open("a.txt")
if err != nil {
fmt.Println("เปิดไม่ได้:", err)
return err
}
// ตรงนี้ err == nil แปลว่าปกติ ใช้ f ต่อได้nil = ว่าง = ไม่พัง กฎเหล็ก: เจอ err เช็คเลย อย่าปล่อยผ่าน อย่า _ ทิ้งถ้าไม่แน่ใจ
import "errors"
errors.New("อายุติดลบไม่ได้")
fmt.Errorf("เปิด %s ไม่ได้: %w", name, err) // %w = ห่ออันเก่าไว้ แกะดูได้
// %v = แค่พิมพ์ %w = ห่อด้วยห่อหลายชั้นเหมือนซองจดหมายซ้อนกัน ยังตามกลับไปหาต้นตอได้
if errors.Is(err, os.ErrNotExist) {
// ไฟล์ไม่มี ไม่ใช่พังแบบอื่น
}
var pathErr *os.PathError
if errors.As(err, &pathErr) {
fmt.Println("พังที่:", pathErr.Path)
}Is = ถามว่าไส้ในใช่คนนี้ไหม (เทียบ sentinel)As = ดึงตัวข้างในออกมาใช้var ErrNoStock = errors.New("ของหมด") // sentinel ไว้ Is
type AgeError struct{ Age int }
func (e *AgeError) Error() string { return fmt.Sprintf("อายุ %d ใช้ไม่ได้", e.Age) }
// คืน: return &AgeError{Age: age}
// เช็ค: var ae *AgeError; if errors.As(err, &ae) { ... }ทริก: เมธอด Unwrap() error หรือ Is/As แบบกำหนดเองได้ถ้าอยากให้เทียบพิเศษ (ขั้นสูง ข้ามก่อนได้)
panic = ชักปลั๊ก ใช้เมื่อไปต่อไม่ได้จริงๆ (config ผิดตั้งแต่เปิด โปรแกรมเมอร์เขียนผิด)return error อย่า panicrecover + defer ไว้กันตายทั้งเซิร์ฟเวอร์:%w บอกว่าพังขั้นไหนIs not-exist → 404 / ที่เหลือ → 500 อย่าโชว์ stack ให้ usergo vet ./... ก่อนส่ง (จับ %w ผิด / print ผิด)อ้างอิง: Effective Go #errors, Go 1.27.1 security fixes crypto/x509 net/url os
e1 := errors.New("อ่าน config ไม่ได้")
e2 := errors.New("ต่อ DB ไม่ได้")
err := errors.Join(e1, e2)
fmt.Println(err) // พิมพ์สองบรรทัดต่อกัน
if errors.Is(err, e1) {
fmt.Println("มี e1 ซ่อนอยู่ในนั้น")
}ใช้ตอน validate หลายช่องพร้อมกัน อยากคืนทุกข้อผิดทีเดียว
type StockError struct{ Item string }
func (e *StockError) Error() string { return "ของหมด: " + e.Item }
func statusOf(err error) int {
if errors.Is(err, os.ErrNotExist) {
return 404
}
var se *StockError
if errors.As(err, &se) {
return 409 // ของหมด = conflict
}
return 500
}func safe(h http.HandlerFunc) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
defer func() {
if rec := recover(); rec != nil {
slog.Error("กู้ panic แล้ว", "err", rec)
http.Error(w, "server error", http.StatusInternalServerError)
}
}()
h(w, r)
}
}_ ทิ้งถ้าไม่แน่ใจ%w ทุกครั้ง จะได้ตามรอยกลับไปหาต้นตอได้Is/As อย่าใช้ == (ห่อหลายชั้นแล้ว == เทียบไม่เจอ)var ErrX = ...) เก็บไว้ที่เดียว ใช้ซ้ำทั้งโปรเจกต์errors.Join (เช่น validate ฟอร์มหลายช่อง)%w 3 ชั้น แล้วใช้ Is เช็ก os.ErrNotExistsafe ครอบ handler ที่ panic แล้วเทสต์ว่า server ไม่ตาย