Procs و Lambdas
في الدرس السابق تعلمنا كيف نستخدم yield لتنفيذ الكتل المُمرَّرة للدوال. لكن ماذا لو أردنا تخزين كتلة برمجية واستخدامها لاحقاً؟ هنا تأتي Procs و Lambdas!
ما هو Proc؟
Proc هو كائن يُمثّل كتلة برمجية. بمعنى آخر، هو طريقة لتخزين كتلة في متغير!
طرق إنشاء Proc
طرق استدعاء Proc
ما هو Lambda؟
Lambda هو نوع خاص من Proc مع قواعد أكثر صرامة. يتصرف بشكل أقرب للدوال العادية.
Lambda مع معاملات
الفرق بين Proc و Lambda
هناك فرقان رئيسيان:
1. فحص عدد المعاملات
Lambda تتحقق من عدد المعاملات بصرامة:
2. سلوك return
هذا الفرق مهم جداً:
الفرق:
returnفي Proc يُنهي الدالة المُحيطةreturnفي Lambda يُنهي Lambda فقط
جدول المقارنة
| الميزة | Proc | Lambda |
|---|---|---|
| فحص المعاملات | متساهل (يقبل أي عدد) | صارم (يجب تطابق العدد) |
| سلوك return | يُنهي الدالة المُحيطة | يُنهي Lambda فقط |
| الإنشاء | Proc.new { } أو proc { } | lambda { } أو -> { } |
| التحقق من النوع | obj.lambda? يُرجع false | obj.lambda? يُرجع true |
تحويل الكتل إلى Procs
استخدام & في تعريف الدالة
استخدام & عند الاستدعاء
اختصار الرموز
تخزين Procs وإعادة استخدامها
إحدى أهم فوائد Procs: يمكن تخزينها وتمريرها!
تخزين في Hash
Closures: الإغلاق
Procs و Lambdas تحتفظ بالسياق الذي أُنشئت فيه:
مثال: عداد
أمثلة عملية
مثال 1: نظام أحداث بسيط
مثال 2: تصفية مخصصة
مثال 3: حساب مرن
متى تستخدم أيهما؟
| الحالة | الاختيار | السبب |
|---|---|---|
| كتلة بسيطة تُمرر لدالة | الكتلة العادية { } | أبسط وأوضح |
| تخزين كتلة لاستخدامها لاحقاً | Proc أو Lambda | كلاهما يعمل |
| تحتاج سلوك مشابه للدالة | Lambda | فحص صارم للمعاملات |
| تحتاج مرونة في المعاملات | Proc | يقبل أي عدد |
| return يجب أن يُنهي الدالة المُحيطة | Proc | سلوك return الخاص |
| return يجب أن يُنهي الكتلة فقط | Lambda | سلوك return العادي |
القاعدة العامة
استخدم Lambda في معظم الحالات لأنها أكثر أماناً وتتصرف كالدوال العادية.
أخطاء شائعة
1. نسيان call
2. خلط return
3. نسيان عدد المعاملات مع Lambda
جدول ملخص
| المفهوم | الصياغة | مثال |
|---|---|---|
| إنشاء Proc | Proc.new { } | p = Proc.new { puts "!" } |
| إنشاء Proc (اختصار) | proc { } | p = proc { puts "!" } |
| إنشاء Lambda | lambda { } | l = lambda { puts "!" } |
| إنشاء Lambda (سهم) | -> { } | l = -> { puts "!" } |
| Lambda مع معاملات | ->(x) { } | l = ->(n) { n * 2 } |
| استدعاء | .call() | p.call(5) |
| تحويل كتلة لـ Proc | &block | def foo(&block) |
| تحويل Proc لكتلة | &proc | arr.map(&my_proc) |
| فحص النوع | .lambda? | obj.lambda? |
تمرين: Procs و Lambdas
حان وقت التطبيق! في محرر الشيفرة على اليسار:
المطلوب:
- أنشئ Lambda اسمه
squareيُربّع الرقم (n ** 2) - أنشئ Proc اسمه
greetيطبع تحية باسم الشخص - استخدم
squareمعmapلتربيع أرقام [1, 2, 3, 4, 5] - استدعِ
greetمع اسم "روبي"
الناتج المتوقع:
تلميحات:
- Lambda:
square = ->(n) { n ** 2 } - Proc:
greet = Proc.new { |name| puts "مرحباً #{name}!" } - استخدم
&squareلتمرير Lambda لـ map - استخدم
greet.call("روبي")لاستدعاء Proc
تذكّر: Procs و Lambdas تُحوّل الكتل إلى كائنات يمكن تخزينها وتمريرها. Lambda أكثر صرامة وأماناً، بينما Proc أكثر مرونة!