ממשק error
חלק מהיחידה תכנות מונחה עצמים במסלול ה-GO של Coddy. שיעור 52 מתוך 107.
ב-Go, שגיאות מטופלות באמצעות ממשק מובנה בשם error. הממשק הזה פשוט להפליא. הוא דורש רק מתודה אחת:
type error interface {
Error() string
}כל טיפוס שמממש מתודה Error() שמחזירה מחרוזת, עומד באופן אוטומטי בממשק error. כך פועלת מערכת הממשקים של Go: אין צורך בהצהרה מפורשת.
הדרך הנפוצה ביותר ליצור שגיאות היא באמצעות החבילה errors:
import "errors"
func Divide(a, b int) (int, error) {
if b == 0 {
return 0, errors.New("cannot divide by zero")
}
return a / b, nil
}פונקציות Go מחזירות בדרך כלל שגיאה כערך ההחזרה האחרון שלהן. כשלא מתרחשת שגיאה, מחזירים nil. לאחר מכן, הקוד הקורא בודק אם השגיאה אינה nil לפני שהוא ממשיך:
result, err := Divide(10, 0)
if err != nil {
fmt.Println("Error:", err.Error())
return
}
fmt.Println("Result:", result)אפשר גם להשתמש ב־fmt.Errorf כדי ליצור הודעות שגיאה מעוצבות:
func GetUser(id int) (string, error) {
if id <= 0 {
return "", fmt.Errorf("invalid user id: %d", id)
}
return "Alice", nil
}הדפוס הזה של החזרת שגיאות במקום זריקת חריגות הוא יסודי ב-Go. הוא הופך את הטיפול בשגיאות למפורש ומאלץ אותך להביא בחשבון מה קורה כשדברים משתבשים: היבט מרכזי בכתיבת קוד מונחה עצמים ועמיד.
אתגר
קלנבנה מערכת חשבון בנק שמדגימה את דפוס הטיפול בשגיאות של Go. תיצרו חשבון פשוט שמאמת פעולות ומחזיר שגיאות ברורות כשמשהו משתבש.
תארגנו את הקוד בשני קבצים:
account.go: צרו struct בשםBankAccountעם שדה מיוצאOwner(מחרוזת) ושדה לא מיוצאbalance(float64). ממשו את הפעולות הבאות:NewBankAccount(owner string, initialDeposit float64) (*BankAccount, error)- פונקציית בנאי שמחזירה שגיאה עם ההודעה"initial deposit must be positive"אם ההפקדה הראשונית היא אפס או שלילית. אחרת, צרו והחזירו את החשבון.Deposit(amount float64) error- מוסיפה כסף ליתרה. החזירו שגיאה עם ההודעה"deposit amount must be positive"אם הסכום הוא אפס או שלילי.Withdraw(amount float64) error- מושכת כסף מהיתרה. החזירו שגיאה עם ההודעה"withdrawal amount must be positive"אם הסכום הוא אפס או שלילי, או"insufficient funds"אם היתרה קטנה מסכום המשיכה.Balance() float64- מחזירה את היתרה הנוכחית
main.go: קראו את פרטי החשבון ואת סכומי העסקאות מהקלט. נסו ליצור חשבון ולבצע פעולות. אחרי כל פעולה, הדפיסו הודעת הצלחה או הודעת שגיאה.
הקלט הבא יסופק:
- שורה 1: שם בעל החשבון
- שורה 2: סכום ההפקדה הראשונית
- שורה 3: סכום ההפקדה
- שורה 4: סכום המשיכה
הדפיסו את התוצאה של כל פעולה:
- אחרי יצירת החשבון:
Account created for [Owner] with balance: $[balance]אוError: [error message] - אחרי הפקדה:
Deposited successfully. New balance: $[balance]אוError: [error message] - אחרי משיכה:
Withdrew successfully. New balance: $[balance]אוError: [error message]
עצבו את כל ערכי היתרה עם שתי ספרות אחרי הנקודה העשרונית. אם יצירת החשבון נכשלת, דלגו על הפעולות שנותרו.
לדוגמה, עבור Alice, 100, 50 ו-200, הפלט שלכם צריך להיות:
Account created for Alice with balance: $100.00
Deposited successfully. New balance: $150.00
Error: insufficient fundsועבור Bob, -50, 25 ו-10, הפלט שלכם צריך להיות:
Error: initial deposit must be positiveנסו בעצמכם
package main
import (
"bufio"
"fmt"
"os"
"strconv"
"strings"
)
func main() {
reader := bufio.NewReader(os.Stdin)
// קרא את שם בעל החשבון
ownerName, _ := reader.ReadString('\n')
ownerName = strings.TrimSpace(ownerName)
// קרא את ההפקדה הראשונית
initialDepositStr, _ := reader.ReadString('\n')
initialDeposit, _ := strconv.ParseFloat(strings.TrimSpace(initialDepositStr), 64)
// קרא את סכום ההפקדה
depositStr, _ := reader.ReadString('\n')
depositAmount, _ := strconv.ParseFloat(strings.TrimSpace(depositStr), 64)
// קרא את סכום המשיכה
withdrawStr, _ := reader.ReadString('\n')
withdrawAmount, _ := strconv.ParseFloat(strings.TrimSpace(withdrawStr), 64)
// TODO: צור חשבון בנק חדש באמצעות NewBankAccount
// אם יש שגיאה, הדפס "Error: [error message]" וסיים את הפעולה
// אם הפעולה הצליחה, הדפס "Account created for [Owner] with balance: $[balance]"
// TODO: נסה להפקיד את סכום ההפקדה
// אם יש שגיאה, הדפס "Error: [error message]"
// אם הפעולה הצליחה, הדפס "Deposited successfully. New balance: $[balance]"
// TODO: נסה למשוך את סכום המשיכה
// אם יש שגיאה, הדפס "Error: [error message]"
// אם הפעולה הצליחה, הדפס "Withdrew successfully. New balance: $[balance]"
// זכור לעצב את ערכי היתרה עם שתי ספרות אחרי הנקודה העשרונית באמצעות fmt.Printf("%.2f", balance)
_ = ownerName
_ = initialDeposit
_ = depositAmount
_ = withdrawAmount
}
השיעור הזה כולל חידון קצר. התחילו את השיעור כדי לענות עליו ולעקוב אחרי ההתקדמות.
כל השיעורים ביחידה תכנות מונחה עצמים
1יסודות OOP ב-Go
קבצים חיצונייםסביבת העבודה והמודולים של Goחבילות וייבואשמות מיוצאים לעומת שמות לא מיוצאיםמבוא ל-OOP ב-GoStructs כמחלקותהגדרת מתודות עבור Structsמקבלי Pointer לעומת Valueאתחול Structפונקציות Constructorחזרה – מחשבון פשוט4ממשקים
מבוא לממשקיםמימוש משתמעממשק כחוזהממשק ריק (any)אימות טיפוסמתג טיפוסיםהרכבת ממשקיםממשקי Stringer ו-Errorסיכום – מחשבון צורות7כימוס
שדות מיוצאים לעומת שדות לא מיוצאיםכימוס ברמת החבילהמתודות Getter ו-Setterהסתרת מידע ב-Goסיכום – רשומות תלמידים10Generics (Go 1.18 ומעלה)
מבוא ל־Genericsפרמטרים של טיפוסיםאילוצי טיפוסיםמבנים גנרייםפתרון עוקף למתודות גנריותסיכום – אוסף גנרי2העמקה בסוגים וב-Structs
סוגים בסיסיים ומורכביםהגדרות של סוגים מותאמים אישיתתגיות StructStructs אנונימייםStructs מקונניםערכי אפס וברירות מחדלסיכום – ספר אנשי קשר5קומפוזיציה במקום ירושה
למה ב-Go אין ירושהיסודות הטמעת Structקידום מתודותהטמעת כמה Structsהטמעה לעומת אגרגציההסתרת מתודות מוטמעותסיכום – היררכיית עובדים8טיפול בשגיאות ו-OOP
ממשק errorסוגי שגיאות מותאמים אישיתעטיפת שגיאות (fmt.Errorf)שגיאות Sentinelerrors.Is() ו-errors.As()Panic, Defer ו-Recoverסיכום – מנתח קבצים11ספרייה סטנדרטית ותכנות מונחה עצמים
io.Reader ו-io.Writersort.Interfaceהממשק fmt.Stringerencoding/json עם מבניםהממשק http.Handlerסיכום – מודלים של REST API3מצביעים וזיכרון
יסודות המצביעים ב-Goמצביעים למבניםהעברה לפי ערך לעומת לפי הפניההפונקציה new()איסוף אשפה ב-Goסיכום - בונה רשימה מקושרת6פולימורפיזם ב-Go
פולימורפיזם באמצעות ממשקיםטיפוס ברווז ב-Goכללי התאמה לממשקאוספים פולימורפייםהזרקת תלויותסיכום - מעבד תשלומים9מקביליות ו-OOP
יסודות GoroutinesChannels ותקשורתChannel עם חוצץ לעומת ללא חוצץפקודת Selectsync.Mutex ו-sync.RWMutexsync.WaitGroupתכנון Struct בטוח לשימוש במקבילסיכום - מאגר עובדים12מושגים מתקדמים בתכנות מונחה עצמים
דפוס האפשרויות הפונקציונליותדפוס Builder ב-Goשרשור מתודותכינויי טיפוסים לעומת הגדרותיסודות Reflectionסקירה כללית של יצירת קודתרגלו בעצמכם: קומפיילר Go אונליין