فهم الـ Closures
جزء من قسم Logic & Flow في رحلة Dart على Coddy — الدرس 46 من 65.
الـ closure هو نوع خاص من الدوال التي "تتذكر" المتغيرات من المكان الذي أُنشئت فيه، حتى بعد انتهاء تنفيذ ذلك السياق الأصلي. فكر فيها كدالة تحمل معها جزءاً من مكان نشأتها أينما ذهبت.
عندما تقوم بإنشاء دالة داخل دالة أخرى، فإن الدالة الداخلية تمتلك صلاحية الوصول إلى متغيرات الدالة الخارجية. وما يجعل هذا "closure" هو أن صلاحية الوصول هذه تستمر حتى بعد انتهاء تنفيذ الدالة الخارجية.
Function createGreeting(String name) {
return () {
return "Hello, $name!";
};
}في هذا المثال، الدالة المجهولة (anonymous function) التي يتم إرجاعها بواسطة createGreeting هي closure. فهي تلتقط المعامل name من النطاق المحيط بها. وحتى بعد انتهاء createGreeting من التنفيذ، تظل الدالة المُرجعة تتذكر ما كانت عليه قيمة name.
تعد الـ Closures مفيدة للغاية لإنشاء وظائف متخصصة أو الحفاظ على الحالة بطريقة نظيفة. فهي تتيح لك بناء وظائف مخصصة بناءً على البيئة التي تم إنشاؤها فيها، مما يجعل الكود الخاص بك أكثر مرونة وقوة.
التحدي
سهلقم بإنشاء برنامج يوضح مفهوم الإغلاقات (closures) من خلال بناء نظام منشئ رسائل مخصص. سيقوم برنامجك بإنشاء دوال "تتذكر" معلومات محددة وتستخدم تلك المعلومات لإنشاء رسائل مخصصة حتى بعد انتهاء السياق الأصلي.
- اقرأ مدخلاً نصياً يمثل اسم الشخص
- اقرأ مدخلاً نصياً يمثل نوع التحية (
"formal"، أو"casual"، أو"friendly") - اقرأ مدخلاً نصياً يمثل اسم الشركة
- أنشئ دالة تسمى
createMessageGeneratorتأخذ الاسم ونوع التحية كمعاملات - يجب أن تعيد الدالة
createMessageGeneratorدالة أخرى (إغلاق/closure) تقوم بما يلي: - تأخذ اسم الشركة كمعامل لها
- تستخدم الاسم ونوع التحية من نطاق (scope) الدالة الخارجية
- تعيد رسالة منسقة بناءً على نوع التحية:
- لـ
"formal":"Dear [name], we are pleased to welcome you to [company]." - لـ
"casual":"Hey [name]! Welcome to [company]!" - لـ
"friendly":"Hi [name], so glad you joined [company]!" - استدعِ الدالة
createMessageGeneratorمع مدخلات الاسم ونوع التحية للحصول على دالة الإغلاق الخاصة بك - استدعِ دالة الإغلاق الناتجة مع مدخل اسم الشركة لإنشاء الرسالة
- اعرض النتائج بالتنسيق الدقيق الموضح أدناه
على سبيل المثال، إذا كانت المدخلات هي "Alice"، و "formal"، و "TechCorp"، يجب أن يخرج برنامجك:
Message Generator System
========================
Creating message generator for: Alice
Greeting type: formal
Company: TechCorp
========================
Generated message: Dear Alice, we are pleased to welcome you to TechCorp.
Message generation completed successfullyإذا كانت المدخلات هي "Bob"، و "casual"، و "StartupXYZ"، يجب أن يخرج برنامجك:
Message Generator System
========================
Creating message generator for: Bob
Greeting type: casual
Company: StartupXYZ
========================
Generated message: Hey Bob! Welcome to StartupXYZ!
Message generation completed successfullyإذا كانت المدخلات هي "Carol"، و "friendly"، و "InnovateLab"، يجب أن يخرج برنامجك:
Message Generator System
========================
Creating message generator for: Carol
Greeting type: friendly
Company: InnovateLab
========================
Generated message: Hi Carol, so glad you joined InnovateLab!
Message generation completed successfullyيجب أن يوضح برنامجك مفهوم الإغلاقات (closures) من خلال إنشاء دالة تعيد دالة أخرى. يجب أن تتمتع الدالة المعادة (الإغلاق) بإمكانية الوصول إلى المتغيرات من نطاق الدالة الخارجية (الاسم ونوع التحية) حتى بعد انتهاء تنفيذ الدالة الخارجية. استخدم الجمل الشرطية لتحديد تنسيق الرسالة المناسب بناءً على مدخل نوع التحية.
ورقة مرجعية
الـ closure هي دالة "تتذكر" المتغيرات من المكان الذي أُنشئت فيه، حتى بعد انتهاء تشغيل السياق الأصلي.
عندما تقوم بإنشاء دالة داخل دالة أخرى، يكون للدالة الداخلية حق الوصول إلى متغيرات الدالة الخارجية. ويستمر هذا الوصول حتى بعد اكتمال تنفيذ الدالة الخارجية.
Function createGreeting(String name) {
return () {
return "Hello, $name!";
};
}في هذا المثال، الدالة المجهولة التي تعيدها createGreeting هي closure. فهي تلتقط المعامل name من النطاق المحيط بها. وحتى بعد انتهاء تشغيل createGreeting، تظل الدالة المعادة تتذكر قيمة name.
تعد الـ closures مفيدة لإنشاء دوال متخصصة أو الحفاظ على الحالة بطريقة نظيفة. فهي تسمح لك ببناء دوال مخصصة بناءً على البيئة التي أُنشئت فيها.
جرّب بنفسك
import 'dart:io';
void main() {
// قراءة المدخلات
String? name = stdin.readLineSync();
String? greetingType = stdin.readLineSync();
String? company = stdin.readLineSync();
// عرض ترويسة النظام
print("Message Generator System");
print("========================");
print("Creating message generator for: $name");
print("Greeting type: $greetingType");
print("Company: $company");
print("========================");
// TODO: اكتب الكود الخاص بك أدناه
// إنشاء دالة createMessageGenerator التي تعيد closure
// استدعاء الدالة وتوليد الرسالة
// إخراج النتائج النهائية
print("Generated message: \$message");
print("Message generation completed successfully");
}يتضمن هذا الدرس اختبارًا قصيرًا. ابدأ الدرس للإجابة عليه وتتبّع تقدمك.
جميع دروس Logic & Flow
1التعامل المتقدم مع القوائم
خصائص القائمة: first و lastحالة القائمة: isEmpty و isNotEmptyعكس القائمةالإضافة إلى القائمة: insertالحذف من القائمة: removeWhereالبحث في القائمة: indexOfفرز القائمةخلط القائمةملخص - منظم القوائم4معالجة الـ Map المتقدمة
التكرار عبر الـ Mapالتحقق من المفاتيح والقيمخصائص الـ Map: keys و valuesإضافة مشروطة: putIfAbsentإزالة العناصر من الـ Mapالـ Maps المتداخلةمراجعة - تحديث المخزون2عمليات القوائم الوظيفية
التحويل باستخدام 'map'التصفية باستخدام 'where'استخدام '.toList()'التحقق من الشروط باستخدام 'any'الشروط باستخدام 'every'البحث باستخدام 'firstWhere'مراجعة - تصفية البيانات5مشروع: حاسبة عربة التسوق
إعداد المشروعإضافة العناصر إلى العربة3المجموعات
ما هي المجموعة؟إنشاء مجموعةالإضافة والحذف من المجموعاتالتحقق من وجود عناصر في المجموعةتحويل قائمة إلى مجموعةاتحاد المجموعاتتقاطع المجموعاتالفرق بين المجموعاتمراجعة - قائمة ضيوف فريدة