Menu
Coddy logo textTech

עטיפת שגיאות (fmt.Errorf)

חלק מהיחידה תכנות מונחה עצמים במסלול ה-GO של Coddy. שיעור 54 מתוך 107.

כאשר שגיאות עוברות דרך שכבות מרובות של היישום שלך, חשוב לדעת היכן מקורה של שגיאה. הפונקציה fmt.Errorf של Go, עם הפועל %w, מאפשרת לך לעטוף שגיאות תוך שימור השגיאה המקורית והוספת הקשר.

עטיפת שגיאות יוצרת שרשרת של שגיאות. כל שכבה יכולה להוסיף מידע על הפעולה שהיא ניסתה לבצע כשהשגיאה התרחשה:

func ReadConfig(filename string) error {
    data, err := os.ReadFile(filename)
    if err != nil {
        return fmt.Errorf("reading config file: %w", err)
    }
    // עבד את הנתונים...
    return nil
}

הפועל %w הוא מיוחד. הוא עוטף את השגיאה המקורית בתוך השגיאה החדשה. זה שונה מ־%v, שרק ממיר את השגיאה למחרוזת ומאבד את הזהות של השגיאה המקורית.

func LoadSettings() error {
    err := ReadConfig("settings.json")
    if err != nil {
        return fmt.Errorf("loading settings: %w", err)
    }
    return nil
}

כש־LoadSettings נכשלת, הודעת השגיאה מציגה את כל השרשרת: "loading settings: reading config file: open settings.json: no such file or directory". כל שכבה מוסיפה הקשר, וכך קל הרבה יותר לנפות שגיאות.

השגיאה העטופה עדיין מכילה בתוכה את השגיאה המקורית. בשיעור הבא תלמדו כיצד להסיר את העטיפה מהשגיאות האלה ולבדוק מה יש בתוכן באמצעות errors.Is() ו-errors.As().

challenge icon

אתגר

קל

בואו נבנה מערכת לעיבוד הזמנות שמדגימה עטיפת שגיאות בכמה שכבות. תיצרו שרשרת של פונקציות שבה כל שכבה מוסיפה הקשר לשגיאות, וכך קל לאתר בדיוק היכן מתרחשות בעיות.

תארגנו את הקוד בשני קבצים:

  • orders.go: צרו את הלוגיקה לעיבוד הזמנות, עם כמה שכבות שעוטפות שגיאות כשהן עוברות כלפי מעלה.

    ממשו שלוש פונקציות שיוצרות שרשרת עיבוד:

    • ValidateItem(itemID string) error - מחזירה שגיאה עם ההודעה "item not found" אם הערך של itemID הוא "INVALID", אחרת מחזירה nil
    • ProcessOrder(orderID, itemID string) error - קוראת ל־ValidateItem. אם היא מחזירה שגיאה, עטפו אותה בהקשר: "processing order [orderID]: %w". אחרת, החזירו nil
    • SubmitOrder(customerName, orderID, itemID string) error - קוראת ל־ProcessOrder. אם היא מחזירה שגיאה, עטפו אותה בהקשר: "submitting order for [customerName]: %w". אחרת, החזירו nil

    כל שכבה צריכה להשתמש ב־fmt.Errorf עם הפועל %w כדי לעטוף את השגיאה מהשכבה שמתחתיה וכך לבנות שרשרת של הקשרים.

  • main.go: קראו את פרטי ההזמנה מהקלט, קראו ל־SubmitOrder והציגו את התוצאה. אם מתרחשת שגיאה, הדפיסו את שרשרת השגיאות המלאה. אם הפעולה מצליחה, הדפיסו הודעת אישור.

הקלטים הבאים יסופקו:

  • שורה 1: שם הלקוח
  • שורה 2: מזהה ההזמנה
  • שורה 3: מזהה הפריט

הדפיסו את התוצאה:

  • אם מתרחשת שגיאה: Error: [full error chain]
  • אם הפעולה מצליחה: Order [orderID] submitted successfully for [customerName]

לדוגמה, בהינתן Alice, ORD-123 ו־INVALID, הפלט שלכם צריך להיות:

Error: submitting order for Alice: processing order ORD-123: item not found

שימו לב איך הודעת השגיאה מציגה את השרשרת המלאה. אפשר לעקוב אחר הבעיה מניסיון שליחת ההזמנה ברמה העליונה, דרך עיבוד ההזמנה, ועד לכשל האימות עצמו. כל שכבה הוסיפה הקשר משלה באמצעות %w.

ובהינתן Bob, ORD-456 ו־ITEM-001, הפלט שלכם צריך להיות:

Order ORD-456 submitted successfully for Bob

נסו בעצמכם

package main

import (
	"bufio"
	"fmt"
	"os"
)

func main() {
	scanner := bufio.NewScanner(os.Stdin)
	
	// קרא את שם הלקוח
	scanner.Scan()
	customerName := scanner.Text()
	
	// קרא את מזהה ההזמנה
	scanner.Scan()
	orderID := scanner.Text()
	
	// קרא את מזהה הפריט
	scanner.Scan()
	itemID := scanner.Text()
	
	// TODO: קרא ל-SubmitOrder עם ערכי הקלט
	// TODO: אם מתרחשת שגיאה, הדפס: Error: [שרשרת השגיאות המלאה]
	// TODO: אם הפעולה הצליחה, הדפס: Order [orderID] submitted successfully for [customerName]
	
	_ = customerName
	_ = orderID
	_ = itemID
}
quiz iconבחנו את עצמכם

השיעור הזה כולל חידון קצר. התחילו את השיעור כדי לענות עליו ולעקוב אחרי ההתקדמות.

כל השיעורים ביחידה תכנות מונחה עצמים

תרגלו בעצמכם: קומפיילר Go אונליין