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

תבנית הקונסטרוקטור 'חדש...'

ל-Go אין מילת מפתח constructor. הכינוס הוא מפעל פונקציה שמחזירה ערך או מצביע מאותחלים כהלכה. מאת שם זה נקרא בדרך כלל NewT (או NewXxx).

תבנית בסיס: NewT

Go
type User struct {
    Name string
    Age  int
}

func NewUser(name string, age int) *User {
    return &User{Name: name, Age: age}
}

u := NewUser("Ada", 36)
fmt.Println(u.Name)

יתרונות על פני &User{...} המילולי הישיר:

  • אתה מרכז אימות וברירות מחדל.
  • אתה יכול לקבל שדות לא מיוצאים ולאכלס אותם רק מהקונסטרוקטור.
  • אתה יכול לשנות את היישום מבלי לשבור את המתקשרים.

בנאי עם אימות: (*T, שגיאה)

כאשר האתחול עלול להיכשל, החזר את (*T, error):

Go
import "errors"

func NewUser(name string, age int) (*User, error) {
    if name == "" {
        return nil, errors.New("nome obbligatorio")
    }
    if age < 0 {
        return nil, errors.New("eta non valida")
    }
    return &User{Name: name, Age: age}, nil
}

u, err := NewUser("Ada", 36)
if err != nil {
    // handle...
}

זהו התבנית האידיומטית עבור כל בנאי עם תנאים מוקדמים: חיבור db, טיפול בקובץ, תצורת שרת וכו'.

מספר בנאים

אם יש לך מספר "דרכים" לבנות, השתמש בשמות תיאוריים:

Go
func NewUser(name string) *User { ... }
func NewUserFromJSON(data []byte) (*User, error) { ... }
func NewAdmin() *User { ... }

אין עומס יתר ב-Go: השם אינו ברור.

אפשרויות פונקציונליות (הצצה מתקדמת)

כאשר ישנם פרמטרים אופציונליים רבים, הדפוס האידיומטי הוא "אפשרויות פונקציונליות":

Go
type Option func(*Server)

func WithPort(p int) Option {
    return func(s *Server) { s.Port = p }
}

func WithTLS(cert, key string) Option {
    return func(s *Server) { s.Cert, s.Key = cert, key }
}

func NewServer(opts ...Option) *Server {
    s := &Server{Port: 8080} // default
    for _, opt := range opts {
        opt(s)
    }
    return s
}

s := NewServer(WithPort(9000), WithTLS("c.pem", "k.pem"))

זה יותר מילולי ממילה מילולית אבל קנה מידה טוב עם רבים אופציונליים פרמטרים ושומר על תאימות לאחור (הוספת Option חדש לא שובר מתקשרים קיימים).

כאשר אתה לא צריך קונסטרוקטור

אם ערך האפס של הסוג כבר שימושי, תן למתקשר להשתמש ב- ישיר מילולי. דוגמה קנונית: ל-sync.Mutex אין בנאי, var m sync.Mutex הוא כבר mutex מוכן לשימוש. אותו דבר עבור bytes.Buffer.

הכלל הוא: "הפוך את ערך האפס לשימושי". אם אתה יכול, לא בנאי חובה.

נסה את זה

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

כתוב את פונקציית היצרן NewUser(מחרוזת שם, גיל int) *משתמש שמחזיר &User{Name: name, Age: age}.

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

השתמש ב'&User{...}' המילולי כדי להחזיר מצביע.

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

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

הפוך את NewUser ל(מחרוזת שם) (*User, error): if name == '' החזר אפס, errors.New('nome obbligatorio').

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

אם יש תנאים מוקדמים, החזר (*T, שגיאה) והחזר אפס + שגיאה בכשל.

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

Quiz#go.m5.l5.e3
מוכן

מהי המוסכמה האידיומטית עבור בנאים ב-Go?

Go
// Which signature is more idiomatic?
אפשרויות תשובה

לְסַכֵּם

  • לא constructor: השתמש בפונקציה NewT (או New בתוך החבילה בעלת שם זהה).
  • החזר *T עבור המארז הפשוט; (*T, error) עם תנאים מוקדמים או אימות.
  • בשגיאה: החזר את nil כמצביע ושגיאת ההסבר כערך השני.
  • אין עומס יתר; השתמש בשמות תיאוריים (NewUserFromJSON, NewAdmin).
  • "הפוך את ערך האפס לשימושי": אם אתה יכול, הבנאי מיותר.
  • דפוס מתקדם עבור פרמטרים אופציונליים רבים: אפשרויות פונקציונליות.