חילוץ שגיאות באמצעות `errors.Is`
חלק מהיחידה לוגיקה וזרימת התוכנית במסלול ה-GO של Coddy. שיעור 40 מתוך 68.
כשעובדים עם שגיאות עטופות, צריך דרך לבדוק אם שגיאה מסוימת קיימת במקום כלשהו בשרשרת השגיאות. הפונקציה errors.Is מספקת בדיוק את היכולת הזאת, ומאפשרת לזהות שגיאות סמן גם כשהן נעטפו כמה פעמים.
הפונקציה errors.Is מקבלת שני פרמטרים: השגיאה שברצונך לבדוק ושגיאת היעד שאתה מחפש. היא מחזירה true אם שגיאת היעד נמצאת במקום כלשהו בשרשרת השגיאות:
var ErrNotFound = errors.New("not found")
wrappedErr := fmt.Errorf("failed to load user: %w", ErrNotFound)
if errors.Is(wrappedErr, ErrNotFound) {
fmt.Println("This is a not found error")
}זו הדרך המודרנית והמומלצת לבדוק שגיאות ספציפיות ב-Go. בניגוד להשוואת מחרוזות או לבדיקות שוויון ישירות, errors.Is פועלת כראוי עם שגיאות עטופות ועוקבת אחר שרשרת השגיאות כדי למצוא התאמות. כך הטיפול בשגיאות שלך נעשה עמיד ואמין, גם כשהשגיאות עוברות דרך כמה שכבות באפליקציה שלך.
אתגר
קלבנה מערכת לניטור חיבור למסד נתונים שמשתמשת ב־errors.Is כדי לזהות שגיאות חיבור מסוימות בשרשראות שגיאות עטופות. האתגר הזה מדגים כיצד להשתמש ב־errors.Is כדי לזהות שגיאות sentinel גם כשהן נעטפו בהקשר נוסף דרך כמה שכבות של היישום.
תקבל שתי קלטים:
- מחרוזת שמכילה פרטים על פעולת מסד הנתונים בפורמט
"database_name,operation,error_type"(לדוגמה,"users_db,connect,connection_timeout") - מחרוזת שמכילה הקשר של היישום בפורמט
"service_name,retry_count"(לדוגמה,"AuthService,3")
המשימה שלך היא:
- להגדיר שלוש שגיאות sentinel באמצעות
errors.New():ErrConnectionTimeoutעם ההודעה"connection timeout"ErrConnectionRefusedעם ההודעה"connection refused"ErrDatabaseNotFoundעם ההודעה"database not found"
- לנתח את הקלט הראשון באמצעות פיצול לפי פסיקים, כדי לקבל את שם מסד הנתונים, הפעולה וסוג השגיאה
- לנתח את הקלט השני באמצעות פיצול לפי פסיקים, כדי לקבל את שם השירות ומספר הניסיונות החוזרים
- ליצור את השגיאה המקורית על סמך סוג השגיאה:
- אם סוג השגיאה הוא
"connection_timeout": להשתמש ב־ErrConnectionTimeout - אם סוג השגיאה הוא
"connection_refused": להשתמש ב־ErrConnectionRefused - אם סוג השגיאה הוא
"database_not_found": להשתמש ב־ErrDatabaseNotFound - לכל סוג שגיאה אחר: להשתמש ב־
errors.New("unknown database error")
- אם סוג השגיאה הוא
- ליצור שגיאה עטופה ברמת מסד הנתונים באמצעות
fmt.Errorfעם%w:"failed to [operation] database [database_name]: %w" - ליצור שגיאה עטופה ברמת השירות:
"[service_name] database operation failed after [retry_count] retries: %w" - להשתמש ב־
errors.Isכדי לבדוק אם השגיאה העטופה הסופית תואמת לכל אחת משגיאות ה־sentinel, ולהציג את התוצאות:"Checking for connection timeout: [true/false]""Checking for connection refused: [true/false]""Checking for database not found: [true/false]"
- להציג את שרשרת השגיאות:
"Error Chain:""Original: [original_error_message]""Database level: [database_level_error_message]""Service level: [service_level_error_message]"
- להציג את ניתוח השגיאה:
"Error Analysis:""Database: [database_name]""Operation: [operation]""Service: [service_name]""Retries: [retry_count]""Error type detected: [detected_error_type]"כאשר detected_error_type הוא אחד מהערכים "Connection Timeout", "Connection Refused", "Database Not Found" או "Unknown Error"
השתמש בחבילת strings כדי לפצל את מחרוזות הקלט לפי פסיקים, בחבילת errors עבור שגיאות sentinel ועבור errors.Is, ובחבילת fmt לעטיפת שגיאות. האתגר הזה מדגים כיצד errors.Is מאפשרת זיהוי אמין של שגיאות ופועלת כראוי עם שגיאות עטופות, ולכן היא חיונית לטיפול אמין בשגיאות ביישומים מורכבים.
נסו בעצמכם
package main
import (
"errors"
"fmt"
"strings"
)
func main() {
// קראו את הקלט
var dbOperation string
var appContext string
fmt.Scanln(&dbOperation)
fmt.Scanln(&appContext)
// נתחו את הקלטים
dbParts := strings.Split(dbOperation, ",")
databaseName := dbParts[0]
operation := dbParts[1]
errorType := dbParts[2]
contextParts := strings.Split(appContext, ",")
serviceName := contextParts[0]
retryCount := contextParts[1]
// TODO: כתבו את הקוד שלכם למטה
// 1. הגדירו את שלוש שגיאות הסמן באמצעות errors.New()
// 2. צרו את השגיאה המקורית לפי סוג השגיאה
// 3. צרו שגיאה עטופה ברמת מסד הנתונים באמצעות fmt.Errorf עם %w
// 4. צרו שגיאה עטופה ברמת השירות
// 5. השתמשו ב-errors.Is כדי לבדוק כל אחת משגיאות הסמן
// 6. הציגו את התוצאות ואת שרשרת השגיאות
}השיעור הזה כולל חידון קצר. התחילו את השיעור כדי לענות עליו ולעקוב אחרי ההתקדמות.
כל השיעורים ביחידה לוגיקה וזרימת התוכנית
1בקרת זרימה מתקדמת
switch עם `fallthrough`יציאה מלולאות מקוננותהמשך לולאה מסוימתהצהרת `goto`סיכום – שליטה מתקדמת בלולאות4פרויקט: רשימת משימות פשוטה
הגדרת הפרויקטהוספת משימה7טיפול בשגיאות לעומק
סוגי שגיאות מותאמים אישיתעטיפת שגיאות באמצעות `%w`חילוץ שגיאות באמצעות `errors.Is`חילוץ שגיאות באמצעות `errors.As`הבנת `panic`שימוש ב־`recover`סיכום — חלוקה בטוחה2מבנים ושיטות
הגדרת שיטות במבניםמקבלי ערךמקבלי מצביעבחירת מקבליםשיטות לעומת פונקציותסיכום — התנהגות המבנים5מפות לעומק
מפות של Structsמצביעים כערכים במפהבדיקה אם מפות הן nilהשוואת מפותסיכום - מונה תדירות מילים8פרויקט: ניהול מלאי פשוט
סקירת הפרויקטבדיקת המלאיתרגלו בעצמכם: קומפיילר Go אונליין