การสร้างข้อผิดพลาดแบบกำหนดเอง
errors.New, fmt.Errorf และข้อผิดพลาดแบบ sentinel
การสร้างข้อผิดพลาดแบบกำหนดเอง เป็นบทเรียน Go Academy ฟรีบน CoddyKit นี่คือบทเรียนที่ 2 จากทั้งหมด 4 บทเรียน คุณสามารถอ่านบทเรียนทั้งหมดด้านล่างฟรี — จากนั้นลองปฏิบัติด้วยตัวคุณเองในเบราว์เซอร์พร้อมตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7 บทเรียนนี้เป็นส่วนหนึ่งของเส้นทางการเรียน Go Academy และความก้าวหน้าของคุณจะซิงค์ข้ามเว็บและแอป CoddyKit คอร์ส Go Academy มีบทเรียนทั้งหมด 4 บทเรียน
เหตุใดจึงต้องใช้ชนิดข้อผิดพลาดแบบกำหนดเอง
ชนิดข้อผิดพลาดแบบกำหนดเองเก็บข้อมูลที่มีโครงสร้างนอกเหนือจากข้อความ ทำให้ผู้เรียกใช้ตรวจสอบและตอบสนองต่อเงื่อนไขข้อผิดพลาดที่เฉพาะเจาะจงได้:
package main
import "fmt"
// Custom error type carries extra context
type HTTPError struct {
StatusCode int
Message string
}
func (e *HTTPError) Error() string {
return fmt.Sprintf("HTTP %d: %s", e.StatusCode, e.Message)
}
func fetch(url string) error {
return &HTTPError{404, "page not found"}
}
func main() {
err := fetch("http://example.com")
fmt.Println(err) // HTTP 404: page not found
}การนำอินเทอร์เฟซของข้อผิดพลาดไปใช้
ชนิดข้อมูลใดก็ตามที่มีเมธอด Error() string จะทำตามอินเทอร์เฟซ error:
package main
import "fmt"
type ValidationError struct {
Field string
Value interface{}
Message string
}
func (e *ValidationError) Error() string {
return fmt.Sprintf("validation: field %q value %v — %s", e.Field, e.Value, e.Message)
}
func validateAge(age int) error {
if age < 0 || age > 150 {
return &ValidationError{"age", age, "must be between 0 and 150"}
}
return nil
}
func main() {
fmt.Println(validateAge(-5))
}ข้อผิดพลาดค่าประจำด้วย errors.New
ข้อผิดพลาดค่าประจำคือตัวแปรระดับแพ็กเกจสำหรับเงื่อนไขข้อผิดพลาดที่รู้จักกันดี:
package main
import ("fmt"; "errors")
var (
ErrNotFound = errors.New("not found")
ErrUnauthorized = errors.New("unauthorized")
ErrAlreadyExists = errors.New("already exists")
)
func getUser(id int) (string, error) {
if id != 1 { return "", ErrNotFound }
return "Alice", nil
}
func main() {
_, err := getUser(99)
if errors.Is(err, ErrNotFound) {
fmt.Println("user does not exist")
}
}fmt.Errorf ด้วย %w สำหรับการห่อข้อผิดพลาด
fmt.Errorf ที่ใช้ %w จะห่อข้อผิดพลาด โดยเก็บข้อผิดพลาดเดิมไว้ให้ errors.Is และ errors.As ใช้งาน:
package main
import ("fmt"; "errors")
var ErrDatabase = errors.New("database error")
func queryDB() error {
return fmt.Errorf("queryDB: %w", ErrDatabase)
}
func main() {
err := queryDB()
fmt.Println(err) // queryDB: database error
fmt.Println(errors.Is(err, ErrDatabase)) // true — unwrapped
}ข้อผิดพลาดแบบกำหนดเองด้วย Unwrap
นำ Unwrap() error ไปใช้กับชนิดข้อผิดพลาดแบบกำหนดเอง เพื่อให้เข้าร่วมในสายโซ่ข้อผิดพลาดได้:
package main
import ("fmt"; "errors")
var ErrNotFound = errors.New("not found")
type QueryError struct {
Query string
Err error
}
func (e *QueryError) Error() string {
return fmt.Sprintf("query %q: %v", e.Query, e.Err)
}
func (e *QueryError) Unwrap() error { return e.Err }
func main() {
err := &QueryError{"SELECT *", ErrNotFound}
fmt.Println(err)
fmt.Println(errors.Is(err, ErrNotFound)) // true
}errors.Is — การตรวจสอบเอกลักษณ์
errors.Is จะเดินไปตามสายโซ่ข้อผิดพลาดเพื่อค้นหาข้อผิดพลาดที่เท่ากับเป้าหมาย:
package main
import ("fmt"; "errors")
var ErrTimeout = errors.New("timeout")
func deepCall() error {
return fmt.Errorf("layer3: %w", fmt.Errorf("layer2: %w", ErrTimeout))
}
func main() {
err := deepCall()
fmt.Println(errors.Is(err, ErrTimeout)) // true — found deep in chain
}errors.As — การดึงชนิดข้อมูล
errors.As ค้นหาข้อผิดพลาดรายการแรกในสายโซ่ที่ตรงกับชนิดข้อมูลเป้าหมาย แล้วกำหนดค่าให้กับเป้าหมายนั้น:
package main
import ("fmt"; "errors")
type PermissionError struct{ User string }
func (e *PermissionError) Error() string { return "permission denied for " + e.User }
func action(user string) error {
return fmt.Errorf("action: %w", &PermissionError{user})
}
func main() {
err := action("bob")
var pe *PermissionError
if errors.As(err, &pe) {
fmt.Println("denied:", pe.User) // denied: bob
}
}การห่อข้อผิดพลาดหลายรายการ (Go 1.20 ขึ้นไป)
Go 1.20 เพิ่ม errors.Join และ fmt.Errorf ที่มี %w หลายรายการสำหรับรวมข้อผิดพลาด:
package main
import ("fmt"; "errors")
func validate(name, email string) error {
var errs []error
if name == "" { errs = append(errs, errors.New("name required")) }
if email == "" { errs = append(errs, errors.New("email required")) }
return errors.Join(errs...)
}
func main() {
err := validate("", "")
fmt.Println(err)
// name required
// email required
}หลักการตั้งชื่อชนิดข้อผิดพลาด
หลักการตั้งชื่อตัวแปรและชนิดข้อผิดพลาดใน Go:
- ตัวแปรข้อผิดพลาดค่าประจำ:
ErrXxx(เช่นErrNotFound) - ชนิดข้อผิดพลาดแบบกำหนดเอง:
XxxError(เช่นValidationError) - ใช้ตัวแปรระดับแพ็กเกจสำหรับข้อผิดพลาดค่าประจำ และใช้ชนิดตัวชี้สำหรับข้อผิดพลาดที่มีข้อมูลมาก
- ส่งออกเพื่อให้ผู้เรียกใช้ใช้กับ
errors.Is/errors.As
เมื่อใดควรใช้แต่ละแนวทาง
การเลือกแนวทางจัดการข้อผิดพลาดที่เหมาะสม:
errors.New— เรียบง่าย ไม่มีข้อมูลเพิ่มเติม และใช้ตรวจสอบเอกลักษณ์ของข้อผิดพลาดค่าประจำfmt.Errorf— ข้อความที่จัดรูปแบบ พร้อมการห่อข้อผิดพลาดที่เลือกใช้ได้- ชนิดข้อมูลแบบกำหนดเอง — เมื่อผู้เรียกใช้ต้องการข้อมูลที่มีโครงสร้าง เช่น ฟิลด์หรือรหัส
errors.Join— รวมข้อผิดพลาดจากการตรวจสอบหลายรายการ
ตรวจสอบอย่างรวดเร็ว
ฟังก์ชันใดใช้ดึงชนิดข้อผิดพลาดที่เฉพาะเจาะจงออกจากสายโซ่ข้อผิดพลาดได้
สรุปทบทวน: ข้อผิดพลาดแบบกำหนดเอง
สรุป:
- นำ
Error() stringไปใช้เพื่อสร้างชนิดข้อผิดพลาดแบบกำหนดเอง - เพิ่ม
Unwrap() errorเพื่อให้เข้าร่วมในสายโซ่ข้อผิดพลาด - ใช้
errors.Isเพื่อตรวจสอบเอกลักษณ์ และerrors.Asเพื่อดึงชนิดข้อมูล - ข้อผิดพลาดค่าประจำ:
ErrXxxส่วนชนิดข้อมูลแบบกำหนดเอง:XxxError errors.Joinใช้รวมข้อผิดพลาดหลายรายการ (Go 1.20 ขึ้นไป)
คำถามที่พบบ่อย
บทเรียน “การสร้างข้อผิดพลาดแบบกำหนดเอง” ฟรีหรือไม่
ใช่ — ข้อความเต็มของ “การสร้างข้อผิดพลาดแบบกำหนดเอง” ฟรีให้อ่านที่นี่บนเว็บ เพื่อปฏิบัติแบบโต้ตอบ (ตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7) และปลดล็อคส่วนที่เหลือของคอร์ส Go Academy ให้อัปเกรดเป็น CoddyKit PRO คอร์ส Go Academy มีบทเรียนทั้งหมด 4 บทเรียน
คุณจะเรียนรู้อะไรในบทเรียน “การสร้างข้อผิดพลาดแบบกำหนดเอง”
errors.New, fmt.Errorf และข้อผิดพลาดแบบ sentinel คุณปฏิบัติ Go Academy ด้วยโค้ดที่ใช้งานได้จริงที่คุณเรียกใช้โดยตรงในเบราว์เซอร์ และติวเตอร์ AI ตลอด 24/7 ตอบคำถามของคุณขณะที่คุณไปผ่านบทเรียน
คุณต้องมีประสบการณ์ก่อนที่จะเริ่มเรียน Go Academy หรือไม่
ไม่จำเป็นต้องมีประสบการณ์มาก่อน Go Academy บน CoddyKit ออกแบบมาสำหรับผู้เริ่มต้นไปจนถึงผู้เรียนขั้นสูง คุณสามารถเริ่มต้นที่นี่หรือเริ่มจากตัวแรกและเรียนด้วยความเร็วของคุณเอง นี่คือบทเรียนที่ 2 จากทั้งหมด 4 บทเรียน
บทเรียน “การสร้างข้อผิดพลาดแบบกำหนดเอง” ใช้เวลานานแค่ไหน
บทเรียน CoddyKit ส่วนใหญ่ใช้เวลาประมาณ 5–10 นาที แต่ละบทเรียนจึงสั้นและเป็นแบบโต้ตอบ คุณสามารถก้าวหน้าอย่างต่อเนื่องและกลับมาเรียนต่อจากตรงที่เพิ่งหยุดบนเว็บและแอปได้เลย
ฉันเขียนและรันโค้ดในบทเรียน Go Academy นี้ได้ไหม
ได้ บทเรียน Go Academy ทุกบทมีตัวแก้ไขโค้ดในตัว คุณจึงเขียนและรันโค้ดจริงได้เลยในเบราว์เซอร์ และได้รับข้อเสนอแนะจาก AI ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ
บทเรียนทั้งหมดในหลักสูตรนี้
- interface error
- การสร้างข้อผิดพลาดแบบกำหนดเอง
- การห่อและคลายข้อผิดพลาด
- panic, recover และ defer