דילוג לתוכן המרכזי
מודול 6 · שיעור 4 מתוך 529/50 בקורס~10 min
שיעורי מודול (4/5)

הממשק של Stringer

fmt.Stringer הוא כנראה הממשק הסטנדרטי הנפוץ ביותר בכולם הספרייה הסטנדרטית של Go. זו ההפגנה המושלמת של הכוח של ממשקים קטנים.

הַגדָרָה

Go
type Stringer interface {
    String() string
}

חתימה אחת. כל סוג שמגדיר String() string עונה זה. ו-fmt מזהה את הממשק הזה: כשאתה מעביר ערך ל fmt.Print*, אם הוא מיישם את Stringer, התוצאה של String() משמש במקום ייצוג ברירת המחדל.

דוּגמָה

Go
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

Go
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 הכלי יוצר דפוס זה באופן אוטומטי.

היזהרו מרקורסיה אינסופית

Go
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() (זה "תצוגה"; זה לא לשנות משהו).

נסה את זה

פעילות גופנית#go.m6.l4.e1
ניסיונות: 0טוען...

יישם String() בנקודה כך שהיא תחזיר (X,Y).

טוען עורך...
הצג רמז

השתמש ב-'fmt.Sprintf' כדי לעצב את השדות.

הפתרון זמין לאחר 3 ניסיונות

פעילות גופנית#go.m6.l4.e2
ניסיונות: 0טוען...

יישם String() בסוג סטטוס (int): 0 → 'OK', 1 → 'WARN', אחרת → 'ERR'.

טוען עורך...
הצג רמז

הפעל את ערך המקלט; זכור לספק ברירת מחדל.

הפתרון זמין לאחר 3 ניסיונות

Quiz#go.m6.l4.e3
מוכן

איזו חתימה צריכה להיות לשיטה כדי לספק את fmt.Stringer?

Go
func (x T) ??? {}
אפשרויות תשובה

לְסַכֵּם

  • fmt.Stringer = interface { String() string }.
  • יישום זה משנה את האופן שבו fmt.Print* מייצג את הסוג.
  • אידיומטי עבור enums (iota), סוגי תחום, קודים/מזהים.
  • לעולם אל תתקשר ל-fmt.Sprintf("%s", t) ב-t בתוך String() (רקורסיה).
  • אמנה: מקבל ערך עבור String() (ללא מוטציה, מונע "הפתעות שנקבעו בשיטה").