סיכום – מנתח קבצים
חלק מהיחידה תכנות מונחה עצמים במסלול ה-GO של Coddy. שיעור 58 מתוך 107.
אתגר
קלבואו נבנה מנתח לקובצי תצורה שמשלב את כל טכניקות הטיפול בשגיאות מהפרק הזה. המנתח שלכם יטפל בכמה תרחישי כשל באמצעות סוגי שגיאות מותאמים אישית, שגיאות סמן, עטיפת שגיאות וניקוי תקין באמצעות defer.
ארגנו את הקוד שלכם בשלושה קבצים:
errors.go: הגדירו את תשתית השגיאות של המנתח.צרו שתי שגיאות סמן:
ErrEmptyContentעם ההודעה"file content is empty"ErrInvalidFormatעם ההודעה"invalid configuration format"
צרו סוג שגיאה מותאם אישית
ParseErrorעם השדותLine(int) ו-Message(string). המתודהError()שלו צריכה להחזיר:parse error at line [Line]: [Message]parser.go: בנו את מנתח התצורה עם טיפול בשגיאות בכמה שכבות.צרו מבנה
ConfigParserעם שדה בוליאניparsedכדי לעקוב אחר השלמת הניתוח בהצלחה.ממשו את המתודות הבאות:
NewConfigParser() *ConfigParser- יוצרת מנתח חדש כאשרparsedמוגדר ל-falseParseLine(lineNum int, line string) error- מאמתת שורה בודדת. אם השורה אינה מכילה את התו=, החזירו*ParseErrorעם מספר השורה וההודעה"missing key-value separator". אחרת, החזירוnil.Parse(content string) error- מתודת הניתוח הראשית ש:- מחזירה
ErrEmptyContentאם התוכן ריק - מחזירה
ErrInvalidFormatאם התוכן אינו מכיל לפחות תו של ירידת שורה אחד - מפצלת את התוכן לפי ירידות שורה וקוראת ל-
ParseLineעבור כל שורה (מספור השורות מתחיל ב-1) - אם
ParseLineמחזירה שגיאה, עטפו אותה באמצעות"parsing configuration: %w"והחזירו אותה - מגדירה את
parsedל-trueבמקרה של הצלחה ומחזירהnil
- מחזירה
Status() string- מחזירה"ready"אםparsedהוא true, ואחרת"not parsed"
main.go: קראו את תוכן התצורה והדגימו בדיקה מקיפה של שגיאות.קראו שתי שורות קלט שמרכיבות יחד את תוכן התצורה (חברו אותן באמצעות ירידת שורה). השתמשו ב-
deferכדי להדפיס תמיד את המצב של המנתח בסוף, בין אם הפעולה הצליחה ובין אם נכשלה.לאחר ניסיון הניתוח, בדקו כל שגיאה באמצעות
errors.Is()וגם באמצעותerrors.As(), כדי לספק משוב ספציפי בהתאם לסיבה לכשל.
הקלטים הבאים יסופקו:
- שורה 1: השורה הראשונה של תוכן התצורה
- שורה 2: השורה השנייה של תוכן התצורה
טפלו בשגיאות באמצעות הודעות ספציפיות:
- אם
errors.Is()מוצאת אתErrEmptyContent: הדפיסוError: No configuration provided - אם
errors.Is()מוצאת אתErrInvalidFormat: הדפיסוError: Configuration must have multiple lines - אם
errors.As()מוצאת*ParseError: הדפיסו את השגיאה המלאה והעטופה, ואז בשורה חדשה הדפיסוFix line [Line]: [Message] - אם הניתוח מצליח: הדפיסו
Configuration parsed successfully
לאחר הטיפול בתוצאה (הצלחה או שגיאה), המצב הנדחה צריך להיות מודפס בשורה חדשה: Parser status: [status]
לדוגמה, עבור host=localhost ו-port=8080, הפלט שלכם צריך להיות:
Configuration parsed successfully
Parser status: readyועבור host=localhost ו-invalid line, הפלט שלכם צריך להיות:
parsing configuration: parse error at line 2: missing key-value separator
Fix line 2: missing key-value separator
Parser status: not parsedנסו בעצמכם
package main
import (
"bufio"
"errors"
"fmt"
"os"
)
func main() {
reader := bufio.NewReader(os.Stdin)
// קרא את השורה הראשונה של התצורה
line1, _ := reader.ReadString('\n')
line1 = line1[:len(line1)-1] // הסר את תו ירידת השורה שבסוף
// קרא את השורה השנייה של התצורה
line2, _ := reader.ReadString('\n')
if len(line2) > 0 && line2[len(line2)-1] == '\n' {
line2 = line2[:len(line2)-1]
}
// חבר את שתי השורות באמצעות תו ירידת שורה כדי ליצור את תוכן התצורה
content := line1 + "\n" + line2
// צור מנתח חדש
parser := NewConfigParser()
// TODO: השתמש ב-defer כדי להדפיס תמיד את מצב המנתח בסוף
// פורמט: "Parser status: [status]"
// TODO: נסה לנתח את התוכן
// TODO: טפל בשגיאות באמצעות errors.Is() ו-errors.As()
// - אם errors.Is() מזהה את ErrEmptyContent: הדפס "Error: No configuration provided"
// - אם errors.Is() מזהה את ErrInvalidFormat: הדפס "Error: Configuration must have multiple lines"
// - אם errors.As() מזהה שגיאה מסוג *ParseError: הדפס את השגיאה העטופה במלואה,
// ואז בשורה חדשה הדפס "Fix line [Line]: [Message]"
// - אם הפענוח מצליח: הדפס "Configuration parsed successfully"
_ = errors.Is // רמז: השתמש ב-errors.Is לשגיאות sentinel
_ = errors.As // רמז: השתמש ב-errors.As עבור סוגי שגיאות מותאמים אישית
_ = fmt.Println
}
כל השיעורים ביחידה תכנות מונחה עצמים
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 אונליין