الأنماط والمطابقة (Patterns & Matching - 3.0)
جزء من قسم البرمجة كائنية التوجه في رحلة Dart على Coddy. الدرس 87 من 110.
قدّمت Dart 3 ميزة مطابقة الأنماط (pattern matching)، وهي طريقة قوية لإجراء destructuring وفحص data في expression واحدة. تتيح لك الأنماط استخراج القيم من الكائنات، والتحقق من بنيتها، وربط المتغيرات — كل ذلك دفعةً واحدة.
لقد رأيتَ بالفعل التفكيك الأساسي باستخدام السجلات. وتوسّع الأنماط ذلك ليشمل العمل مع الكائنات والقوائم والخرائط:
void main() {
// أنماط القوائم
var numbers = [1, 2, 3];
var [a, b, c] = numbers;
print('$a, $b, $c'); // 1, 2, 3
// أنماط الخرائط
var user = {'name': 'Alice', 'age': 30};
var {'name': name, 'age': age} = user;
print('$name is $age'); // أليس هي 30
}تصبح الأنماط قوية بشكل خاص في تعبيرات switch. يمكنك المطابقة حسب النوع والقيمة والبنية في الوقت نفسه:
String describe(Object obj) {
return switch (obj) {
int n when n < 0 => 'Negative number',
int n => 'Positive number: $n',
String s => 'String of length ${s.length}',
[int first, ...] => 'List starting with $first',
_ => 'Something else',
};
}
void main() {
print(describe(-5)); // عدد سالب
print(describe(42)); // عدد موجب: 42
print(describe([1, 2, 3])); // List starting with 1
}تضيف عبارة when شروطًا إلى الأنماط، وتطابق ... العناصر المتبقية في list. تعمل الشرطة السفلية _ كحرف بدل يطابق أي شيء. وبالاقتران مع الأصناف sealed، تتيح الأنماط معالجة شاملة وآمنة من حيث النوع لهياكل البيانات المعقدة.
التحدي
سهللننشئ مصنِّفًا للبيانات يستخدم مطابقة الأنماط لتحليل أنواع مختلفة من input وتصنيفها! ستنشئ نظامًا يمكنه تحديد ووصف هياكل data متنوعة باستخدام ميزات مطابقة الأنماط القوية في Dart 3.
ستنظّم شيفرتك في ملفين:
classifier.dart: أنشئ دالة باسمclassifyتأخذ معاملًا من النوعObjectوتُرجع وصفًا من النوعString. استخدم تعبيرswitchمع مطابقة الأنماط لمعالجة الحالات التالية:- يجب أن تُرجع
Empty listعند وجودlistفارغة[] - يجب أن تُرجع
Single item: [value]عند وجودlistتحتوي علىintegerواحدelementبالضبط - يجب أن تُرجع
Pair: [first] and [second]عند وجودlistتحتوي على عنصرين بالضبط - يجب أن تُرجع
List starting with [first], length: [total length]عند وجودlistتبدأ بـintegerمتبوعًا بمزيد منelements(استخدم نمط الباقي...) - يجب أن تُرجع
[name] is [age] years oldعند وجودmapيحتوي على المفتاحين'name'و'age'(استخدم تفكيك نمطmap) - يجب أن تُرجع
Negative: [value]عند وجودintegerسالب (استخدم عبارةwhen) - يجب أن تُرجع
Zeroعند وجودintegerيساوي صفرًا - يجب أن تُرجع
Positive: [value]لأيintegerآخر - يجب أن تُرجع
Unknown typeلأي قيمة أخرى
- يجب أن تُرجع
main.dart: استورد المصنِّف ووضّح مطابقة الأنماط باستخدامinputمتنوعة. اطبع نتيجة تصنيف كل قيمة من القيم التالية:listفارغة:[]listتحتوي علىelementواحد:[42]listتحتوي على عنصرين:['hello', 'world']listأطول:[1, 2, 3, 4, 5]map:{'name': 'Alice', 'age': 25}- العدد
integer-10 - العدد
integer0 - العدد
integer99
يجمع هذا التحدي بين أنماط list وأنماط map وعبارة when للحراس ونمط الباقي (...) - وهي جميع ميزات مطابقة الأنماط الأساسية في الدرس!
الناتج المتوقع:
Empty list
Single item: 42
Pair: hello and world
List starting with 1, length: 5
Alice is 25 years old
Negative: -10
Zero
Positive: 99جرّب بنفسك
import 'classifier.dart';
void main() {
// TODO: استخدم الدالة classify لتصنيف كل قيمة
// واطبع النتائج
// اختبر بقائمة فارغة
print(classify([]));
// TODO: اختبر بقائمة تحتوي على عنصر واحد: [42]
// TODO: اختبر بقائمة تحتوي على عنصرين: ['hello', 'world']
// TODO: اختبر بقائمة أطول: [1, 2, 3, 4, 5]
// TODO: اختبر بـ map: {'name': 'Alice', 'age': 25}
// TODO: اختبر بالعدد الصحيح -10
// TODO: اختبر بالعدد الصحيح 0
// TODO: اختبر بالعدد الصحيح 99
}
يتضمن هذا الدرس اختبارًا قصيرًا. ابدأ الدرس للإجابة عليه وتتبّع تقدمك.
جميع دروس البرمجة كائنية التوجه
1أساسيات الـ OOP
الملفات الخارجيةالمكتبات والـ Importsمقدمة في الـ OOPالـ Classes مقابل الـ Objectsالكلمة المفتاحية thisالـ Methodsمتغيرات الـ Instanceأساسيات الـ Constructorمراجعة - آلة حاسبة بسيطة4أمان الـ Null
مقدمة في أمان الـ NullNullable مقابل Non-Nullableعاملا الـ ? و !الكلمة المفتاحية Late وأمان الـ Nullالعوامل المدركة للـ Nullأمان الـ Null في الـ Classesمراجعة - نظام ملف تعريف المستخدم7الفئات المجردة والواجهات
الفئات المجردةالدوال المجردةالواجهات في Dartالواجهات الضمنيةالتنفيذ مقابل التوسيعالواجهات المتعددةمراجعة - حاسبة الأشكال10المجموعات والأنماط العامة
نظرة عامة على List و Set و Mapالمجموعات آمنة النوعالفئات العامةالدوال العامةقيود الأنماط العامةIterable و Iteratorملخص - التخزين العام13مفاهيم OOP المتقدمة
التركيب مقابل الوراثة (Composition vs Inheritance)دوال التوسعة (Extension Methods)الأصناف القابلة للاستدعاء (Callable Classes)الأصناف المختومة (Sealed Classes - Dart 3)السجلات (Records - Dart 3)الأنماط والمطابقة (Patterns & Matching - 3.0)التعدادات مع الدوال (Enums with Methods)2المنشئات في Dart
المنشئ الافتراضيالمنشئات المسماةقوائم التهيئةالمنشئات الثابتةالمنشئات المصنعيةالمنشئات الموجهةملخص - بناء الأشكال5التغليف (Encapsulation)
الأعضاء العامة مقابل الخاصةاتفاقية البادئة _الخصوصية على مستوى المكتبةتعمق في Getters و Settersإخفاء المعلوماتمراجعة - سجلات الطلاب8Mixins
مقدمة إلى Mixinsإنشاء Mixinsاستخدام Mixins متعددةالكلمة المفتاحية on في MixinsMixin مقابل الوراثة (Inheritance)Mixin مقابل الواجهة (Interface)مراجعة - نظام الحيوانات (Animal System)3خصائص الـ Class
أعضاء الـ Instance مقابل الـ Staticحقول Final و Constمتغيرات Lateالـ Static Methods والحقولدوال الـ Getters والـ Settersمراجعة - مدير الحساب البنكي6الوراثة
أساسيات الوراثةالكلمة المفتاحية superإعادة تعريف الدوال (Method Overriding)الوسم @overrideالكلمة المفتاحية final Classالدوال البانية والوراثةمراجعة - هيكلية الموظفين9تعدد الأشكال
أساسيات تعدد الأشكالتعدد الأشكال عبر الـ Interfacesالتحقق من النوع أثناء التشغيلالمعاملات is و asالكلمة المفتاحية Covariantملخص - معالج الدفع12البرمجة الكائنية غير المتزامنة (Async OOP)
Futures و async/awaitأساسيات الـ Streamsمتحكمات الـ Streamsالـ Constructors غير المتزامنةالعمليات غير المتزامنة في دوال الكلاسمراجعة - جالب البيانات (Data Fetcher)15أنماط التصميم - الجزء الثاني
نمط الأمرنمط المحولنمط المزيننمط طريقة القالبنمط الحالةنمط التركيبنمط المستودعتدرّب بنفسك: مترجم Dart عبر الإنترنت