Menu
Coddy logo textTech

שגיאות Sentinel

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

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

מגדירים שגיאות זקיף כמשתנים ברמת החבילה, בדרך כלל עם שמות שמתחילים ב־Err:

package user

import "errors"

var (
    ErrNotFound     = errors.New("user not found")
    ErrInvalidEmail = errors.New("invalid email address")
    ErrDuplicate    = errors.New("user already exists")
)

פונקציות מחזירות את השגיאות המוגדרות מראש האלה כאשר מתקיימים תנאים מסוימים:

func FindUser(id int) (*User, error) {
    user, exists := users[id]
    if !exists {
        return nil, ErrNotFound
    }
    return user, nil
}

היתרון של שגיאות זקיף הוא שהקוראים לפונקציה יכולים לבדוק תנאי שגיאה מסוימים על ידי השוואה ישירה של ערכי שגיאה:

user, err := FindUser(42)
if err == ErrNotFound {
    fmt.Println("Creating new user...")
} else if err != nil {
    fmt.Println("Unexpected error:", err)
}

הספרייה הסטנדרטית של Go משתמשת באופן נרחב בשגיאות זקיף. לדוגמה, io.EOF מסמנת את סוף הקלט, ו-sql.ErrNoRows מציינת שתוצאת השאילתה ריקה. התבנית הזאת יוצרת חוזה ברור בין חבילות למשתמשים שלהן לגבי השגיאות שניתן לצפות להן.

עם זאת, בדיקות שוויון פשוטות נכשלות כשעוטפים שגיאות. בשיעור הבא תלמדו איך errors.Is() פותרת את הבעיה הזאת באמצעות בדיקת שרשרת השגיאות כולה.

challenge icon

אתגר

קל

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

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

  • inventory.go: צרו מערכת מלאי עם שגיאות sentinel מוגדרות מראש עבור מקרי כשל נפוצים.

    הגדירו שלוש שגיאות sentinel ברמת החבילה:

    • ErrItemNotFound עם ההודעה "item not found in inventory"
    • ErrOutOfStock עם ההודעה "item is out of stock"
    • ErrInsufficientQuantity עם ההודעה "insufficient quantity available"

    צרו מבנה Inventory שמכיל מפה של שמות פריטים והכמויות שלהם. ממשו את המתודות הבאות:

    • NewInventory() *Inventory - יוצרת מלאי ריק
    • AddItem(name string, quantity int) - מוסיפה פריט או מעדכנת את הכמות שלו
    • GetQuantity(name string) (int, error) - מחזירה את הכמות של פריט, או את ErrItemNotFound אם הוא לא קיים
    • Purchase(name string, quantity int) error - מנסה לרכוש פריטים. החזירו את ErrItemNotFound אם הפריט לא קיים, את ErrOutOfStock אם הכמות הנוכחית היא אפס, או את ErrInsufficientQuantity אם הכמות המבוקשת עולה על המלאי הזמין. במקרה של הצלחה, הפחיתו את הכמות במלאי והחזירו את nil.
  • main.go: קראו את פעולות המלאי מהקלט והדגימו כיצד הקוד הקורא יכול לבדוק אם התקבלה שגיאת sentinel מסוימת באמצעות השוואת שוויון ישירה.

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

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

  • שורה 1: שם הפריט לרכישה
  • שורה 2: הכמות לרכישה

טפלו בתוצאה על ידי בדיקה איזו שגיאה מסוימת הוחזרה:

  • אם err == ErrItemNotFound: הדפיסו Error: Item '[name]' does not exist in our inventory
  • אם err == ErrOutOfStock: הדפיסו Error: Item '[name]' is currently out of stock
  • אם err == ErrInsufficientQuantity: הדפיסו Error: Cannot purchase [quantity] units of '[name]' - not enough in stock
  • אם הפעולה הצליחה: הדפיסו Successfully purchased [quantity] units of '[name]'

לדוגמה, עבור laptop ו-3, הפלט שלכם אמור להיות:

Successfully purchased 3 units of 'laptop'

ועבור phone ו-2, הפלט שלכם אמור להיות:

Error: Item 'phone' does not exist in our inventory

ועבור laptop ו-10, הפלט שלכם אמור להיות:

Error: Cannot purchase 10 units of 'laptop' - not enough in stock

נסו בעצמכם

package main

import (
	"fmt"
)

func main() {
	// קראו את הקלט
	var itemName string
	var quantity int
	fmt.Scanln(&itemName)
	fmt.Scanln(&quantity)

	// צרו מלאי והוסיפו את "laptop" בכמות 5
	inv := NewInventory()
	inv.AddItem("laptop", 5)

	// TODO: נסו לרכוש את הפריט
	// קראו ל־inv.Purchase(itemName, quantity)

	// TODO: בדקו איזו שגיאת sentinel ספציפית הוחזרה באמצעות השוואת שוויון ישירה
	// השתמשו במשפטי if/else if כדי לבדוק:
	// - err == ErrItemNotFound
	// - err == ErrOutOfStock
	// - err == ErrInsufficientQuantity
	// - err == nil (הצלחה)

	// TODO: הדפיסו את ההודעה המתאימה בהתאם לשגיאה
	// אם ErrItemNotFound: fmt.Printf("Error: Item '%s' does not exist in our inventory\n", itemName)
	// אם ErrOutOfStock: fmt.Printf("Error: Item '%s' is currently out of stock\n", itemName)
	// אם ErrInsufficientQuantity: fmt.Printf("Error: Cannot purchase %d units of '%s' - not enough in stock\n", quantity, itemName)
	// אם הפעולה הצליחה: fmt.Printf("Successfully purchased %d units of '%s'\n", quantity, itemName)
}
quiz iconבחנו את עצמכם

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

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

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