שיעורי מודול (4/5)
הממשק של Stringer
fmt.Stringer הוא כנראה הממשק הסטנדרטי הנפוץ ביותר בכולם
הספרייה הסטנדרטית של Go. זו ההפגנה המושלמת של הכוח
של ממשקים קטנים.
הַגדָרָה
type Stringer interface {
String() string
}חתימה אחת. כל סוג שמגדיר String() string עונה
זה. ו-fmt מזהה את הממשק הזה: כשאתה מעביר ערך ל
fmt.Print*, אם הוא מיישם את Stringer, התוצאה של String()
משמש במקום ייצוג ברירת המחדל.
דוּגמָה
type Point struct{ X, Y int }
func (p Point) String() string {
return fmt.Sprintf("(%d,%d)", p.X, p.Y)
}
fmt.Println(Point{1, 2}) // (1,2)
fmt.Printf("%v %s\n", Point{3, 4}, Point{5, 6})
// (3,4) (5,6)אותו ערך מודפס עם עיצוב מותאם אישית ב-%v, %s, Println,
Sprint, log וכו'. הכל רק על ידי הגדרת שיטה אחת.
כשזה הגיוני
- סוגים המדגימים תחום (מזהים, קודים, קואורדינטות, ספירות).
- שגיאות עם ייצוג קריא אנושי (ראה את השיעור הבא בנושא
error). - סוגים שאתה רושם לעתים קרובות ועבורם אתה רוצה פורמט קבוע.
לא לכל דבר: אם הסוג פשוט וייצוג ברירת המחדל זה בסדר, אל תוסיף רעש.
סוגי Enum: דפוס נפוץ עם iota
type Status int
const (
OK Status = iota
WARN
ERR
)
func (s Status) String() string {
switch s {
case OK: return "OK"
case WARN: return "WARN"
case ERR: return "ERR"
default: return "UNKNOWN"
}
}
fmt.Println(OK, WARN, ERR) // OK WARN ERRללא String(), fmt.Println(OK) ידפיס את 0. עם String(),
הוא מדפיס את השם הסמלי. ה-stringer
הכלי יוצר דפוס זה באופן אוטומטי.
היזהרו מרקורסיה אינסופית
type T int
func (t T) String() string {
return fmt.Sprintf("%d", int(t)) // OK: cast to int breaks the recursion
}Stringer על מקלט מצביע
אם ל-String() יש מקלט מצביע, רק *T עונה על Stringer.
עם fmt.Println(t) (ערך), Go מסתכל על קבוצת השיטות של T,
לא מוצא אותו, ומשתמש בפורמט ברירת המחדל. כדי להימנע מכך, ערך
מקלט משמש בדרך כלל עבור String() (זה "תצוגה"; זה לא
לשנות משהו).
נסה את זה
יישם String() בנקודה כך שהיא תחזיר (X,Y).
הצג רמז
השתמש ב-'fmt.Sprintf' כדי לעצב את השדות.
הפתרון זמין לאחר 3 ניסיונות
יישם String() בסוג סטטוס (int): 0 → 'OK', 1 → 'WARN', אחרת → 'ERR'.
הצג רמז
הפעל את ערך המקלט; זכור לספק ברירת מחדל.
הפתרון זמין לאחר 3 ניסיונות
איזו חתימה צריכה להיות לשיטה כדי לספק את fmt.Stringer?
func (x T) ??? {}לְסַכֵּם
fmt.Stringer = interface { String() string }.- יישום זה משנה את האופן שבו
fmt.Print*מייצג את הסוג. - אידיומטי עבור enums (
iota), סוגי תחום, קודים/מזהים. - לעולם אל תתקשר ל-
fmt.Sprintf("%s", t)ב-tבתוךString()(רקורסיה). - אמנה: מקבל ערך עבור
String()(ללא מוטציה, מונע "הפתעות שנקבעו בשיטה").