دروس الوحدة (5/5)
نمط المنشئ `الجديد...`
لا يحتوي Go على كلمة رئيسية constructor. الاتفاقية هي ** مصنع
دالة ** تُرجع قيمة أو مؤشرًا تمت تهيئته بشكل صحيح. بواسطة
يُطلق عليه عادةً اسم NewT (أو NewXxx).
النمط الأساسي: NewT
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):
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...
}هذا هو النمط الاصطلاحي لأي منشئ به الشروط المسبقة: اتصال قاعدة البيانات، مقبض الملف، تكوين الخادم، وما إلى ذلك.
منشئون متعددون
إذا كان لديك "طرق" متعددة للإنشاء، فاستخدم أسماء وصفية:
func NewUser(name string) *User { ... }
func NewUserFromJSON(data []byte) (*User, error) { ... }
func NewAdmin() *User { ... }لا يوجد تحميل زائد في 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 هو بالفعل كائن مزامنة جاهز للاستخدام. نفس الشيء بالنسبة لـ bytes.Buffer.
القاعدة هي: "اجعل القيمة صفر مفيدة". إذا كنت تستطيع، لا منشئ إلزامي.
جربه
اكتب وظيفة المصنع NewUser(name string, age int) *User الذي يُرجع &User{Name: name, Age: age}.
إظهار التلميح
استخدم الحرفي `&User{...}` لإرجاع المؤشر.
الحل متاح بعد 3 من المحاولات
تحويل NewUser إلى (سلسلة اسم) (*مستخدم، خطأ): إذا كان الاسم == '' يُرجع لا شيء، أخطاء. جديد('nome obbligatorio').
إظهار التلميح
إذا كانت هناك شروط مسبقة، قم بإرجاع (*T، خطأ) وإرجاع nil + خطأ عند الفشل.
الحل متاح بعد 3 من المحاولات
ما هو الاصطلاح الاصطلاحي للمنشئين في Go؟
// Which signature is more idiomatic?خلاصة
- لا
constructor: استخدم وظيفةNewT(أوNewداخل الحزمة التي تحمل نفس الاسم). - ارجع
*Tللحالة البسيطة؛(*T, error)بشروط مسبقة أو التحقق من الصحة. - عند حدوث خطأ: قم بإرجاع
nilكمؤشر والخطأ التوضيحي كقيمة ثانية. - لا التحميل الزائد. استخدم أسماء وصفية (
NewUserFromJSON،NewAdmin). - "اجعل القيمة الصفرية مفيدة": إذا استطعت، فإن المنشئ غير ضروري.
- نمط متقدم للعديد من المعلمات الاختيارية: الخيارات الوظيفية.