💡 هذا الدرس يبني على قسم الأصناف (Classes) من درس أساسيات Dart — نفس فكرة الصنف والمُنشئ، بس بصيغة أقصر صارت مستقرة رسميًا بدءًا من Dart 3.13 (يأتي مع Flutter 3.47 المستقرة).
المشكلة: تكرار اسم الحقل ثلاث مرّات
بالصيغة التقليدية، أي حقل بالصنف بتكتب اسمه ونوعه ثلاث مرّات: مرّة كتصريح
حقل، ومرّة بقائمة معاملات المُنشئ (this.x)، وأحيانًا مرّة ثالثة لو
احتجت توثيقه. لصنف بسيط زي Point:
class Point {
final int x;
final int y;
Point(this.x, this.y);
}
الحل: المُنشئ الأساسي (Primary Constructor)
بدءًا من Dart 3.13، تقدر تكتب قائمة المعاملات مباشرة بجانب اسم الصنف —
والمعاملات اللي عليها var أو final بتصبح تلقائيًا حقولًا بالصنف
وجزء من المُنشئ بنفس الوقت. نفس صنف Point أعلاه يصير سطرًا واحدًا:
class Point(final int x, final int y);
لاحظ الفاصلة المنقوطة ; بدل {} — أي صنف بلا جسم إضافي (بدون توابع
أخرى) ينتهي بـ ; مباشرة.
💡 هذا مجرّد اختصار كتابة — لا يضيف أي سلوك جديد. الصنفان أعلاه متطابقان تمامًا وقت التشغيل؛ الفرق فقط عدد الأسطر.
var مقابل final بالمُنشئ الأساسي
نفس قاعدة تصريح الحقول العادية: final يعني القيمة لا تتغيّر بعد
الإنشاء، var يسمح بتعديلها لاحقًا.
class Counter(var int value); // value قابل للتعديل بعد الإنشاء
void main() {
var c = Counter(0);
c.value = 5; // مسموح لأنه var
}
معاملات اختيارية ومسمّاة
المُنشئ الأساسي يدعم نفس صيغ المعاملات الاختيارية ([]) والمسمّاة ({})
اللي تعرفها من الدوال العادية:
// اختياري بقيمة افتراضية
class Point(final int x, [final int y = 0]);
// مسمّى وإجباري
class User(final String name, {required final int age});
مُنشئ مسمّى وثابت (const)
لو احتجت مُنشئًا مسمّى أو ثابتًا (const)، يُكتَب مباشرة بعد اسم الصنف
بنفس ترتيب الصيغة القديمة:
// الصيغة التقليدية
class Point {
final int x;
final int y;
const Point._(this.x, this.y);
}
// المُنشئ الأساسي
class const Point._(final int x, final int y);
جسم إضافي أو initializer list
لو احتجت تابعًا إضافيًا أو تحققًا بـ assert قبل الإنشاء، تقدر تضيف جسم
صنف عادي بجانب المُنشئ الأساسي — القائمة بالهيدر تبقى كما هي:
class Point(final int x, final int y) {
Point.origin() : this(0, 0); // مُنشئ ثانوي يستدعي الأساسي
double get distance => (x * x + y * y).toDouble();
}
💡 أي مُنشئ إضافي غير المُنشئ الأساسي لازم يكون redirecting — يستدعي المُنشئ الأساسي مباشرة أو بشكل غير مباشر، زي
Point.origin()أعلاه. هذا يضمن إنه المُنشئ الأساسي ينفّذ دائمًا مع كل كائن جديد.
أخطاء شائعة
- استخدام
finalعلى معامل عادي (غير مُعلن كحقل) بنيّة منع تعديله محليًا داخل الدالة — هذا صار خطأ ترجمة (compile-time error) بـ Dart 3.13، لأنهfinalبمعامل صار محجوزًا حصرًا للمعاملات المُعلِنة بالمُنشئ الأساسي. البديل لمنع إعادة تعيين معامل عادي هو قاعدة linter الجاهزةparameter_assignments. - نسيان رفع الحد الأدنى لإصدار SDK بملف
pubspec.yamlإلىsdk: '^3.13.0'— الصيغة الجديدة غير متاحة بإصدارات Dart أقدم. - الظن إنه المُنشئ الأساسي يغيّر سلوك الصنف — هو اختصار كتابة فقط، الصنف يعمل بنفس الطريقة تمامًا وقت التشغيل.
🎯 التالي: الخلاصة الشاملة لمسار Flutter وخطواتك بعده.