سؤال
لقد بدأت تعلم روبي, ولقد قرأت بضعة دروس و حتى اشتريت كتاب ("البرمجة روبي 1.9 - عملي للمبرمجين دليل"), و لقد وجدت شيئا جديدا لم أره من قبل في أي من اللغات الأخرى أعرف (أنا أعمل PHP webdeveloper).
كتل & Procs.أعتقد أنني أفهم ما هي عليه ، ولكن ما لا أفهمه هو لماذا هم عظيم جدا, و متى و لماذا يجب استخدامها.في كل مكان أنظر يقولون كتل procs هي ميزة كبيرة في روبي ، ولكن لا فهم لهم.
هل من أحد هنا تعطي مجموع روبي-مبتدئ مثلي بعض تفسيرات ؟
المحلول
هناك الكثير من الأشياء التي هي جيدة عن كتل.المصعد الملعب:كتل اسمحوا لنا بالمرور حول الإجراءات بنفس الطريقة نحن عادة تمر في جميع أنحاء البيانات.
المستوى الأكثر وضوحا هو أنها تتيح لك أشياء مجردة إلى الوظائف التي لن يكون من الممكن خلاف ذلك.على سبيل المثال, دعونا ننظر إلى حالة شائعة حيث لديك قائمة من الأشياء التي تريد تصفية فقط تشمل العناصر التي تطابق بعض المعيار:
int list[50] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50};
int evenNumbers[50] = {0};
int copyIndex = 0;
for (int i = 0; i < 50; i++) {
if (list[i] % 2 == 0) {
evenNumbers[copyIndex++] = list[i];
}
}
هنا هو كيف يمكنك كتابة ذلك في روبي:
list = 1..50
listCopy = list.select {|n| n.even?}
كل مشترك busywork تم نقل التعليمات البرمجية الخاصة بك إلى طريقة ذات معنى الاسم.نحن لا نهتم نسخ مجموعة والذهاب من خلال الفهارس و كل ما نريد قائمة تمت تصفيتها.و هذا ما select
يعطينا.كتلة يسمح لنا بالمرور عادتنا المنطق في هذه الطريقة القياسية.
ولكن التكرار ليست المكان الوحيد حيث هذا "ثقب في الوسط نمط" هو مفيد.على سبيل المثال, إذا كنت تمر كتلة File.open
, ، فإنه سيتم فتح ملف تنفيذ كتلة مع الملف ثم قم بإغلاق الملف لك.
شيء آخر أن كتل تعطينا هي قوية حقا شكل رد.على سبيل المثال, بدون كتل, علينا أن نفعل شيئا مثل هذا (على أساس مدى الحوارات فعلا العمل في الهدف-C الكاكاو):
class Controller
def delete_button_clicked(item)
item.add_red_highlight
context = {:item => item}
dialog = Dialog.new("Are you sure you want to delete #{item}?")
dialog.ok_callback = :delete_OK
dialog.ok_receiver = self
dialog.cancel_callback = :cancel_delete
dialog.cancel_receiver = self
dialog.context = context
dialog.ask_for_confirmation
end
def delete_OK(sender)
delete(sender.context[:item])
sender.dismiss
end
def cancel_delete(sender)
sender.context[:item].remove_red_highlight
sender.dismiss
end
end
تعرض ما لديها.مع كتل يمكن أن نقوم بذلك بدلا من ذلك (على أساس النمط الشائع استخدامها في العديد من روبي المكتبات):
class Controller
def delete_button_clicked(item)
item.add_red_highlight
Dialog.ask_for_confirmation("Are you sure you want to delete #{item}?") do |response|
response.ok { delete item }
response.cancel { item.remove_red_highlight }
end
end
end
هذا هو في الواقع اثنين من مستويات من كتل ـ do...end
كتلة اثنين {}
على غرار كتل.ولكن من يقرأ طبيعي جدا, أليس كذلك ؟ يعمل هذا لأن كتلة يلتقط السياق أنه خلق لذلك لا تحتاج إلى تمرير جميع أنحاء self
و item
.
أما بالنسبة Procs ، انهم مجرد كائن المجمع كتل.ليس كثيرا جدا لهم.
نصائح أخرى
من المهم أن عرض القطع ليس باستخدام طرق للبدء في كتلة التعليمات البرمجية ، كنت تأخذ في الواقع كتلة واستخدامه مثل معلمة في وظيفة.
حتى عند استخدام كل طريقة تكرار عبر مجموعة مثل ذلك:
superOverFlowArray.each { |flow| puts flow }
تقوم بإرسال كتلة {التدفق || يضع تدفق } في كل طريقة.رمز تقول روبي إرسال القيمة الحالية مجموعة إلى هذه الكتلة في مكان التدفق||.
Procs تأخذ كتلة وجعلها في متغير.Procs هي كائن الحالات التي تحمل كتل.كتل مرت كمعلمة إلى proc و يتم تنفيذها عند استدعاء استدعاء الأسلوب على أن بروك سبيل المثال.
حتى هنا هو بروك سبيل المثال:
def category_and_title(category)
Proc.new { |title| "The title is: " + title + " in category: " + category }
end
myFirstTitle = category_and_title("Police Drama")
mySecondTitle = category_and_title("Comedy")
puts myFirstTitle.call("Law and Order")
puts mySecondTitle.call("Seinfeld")
puts myFirstTitle.call("CSI")
بروك سوف تذكر الأصلي الفئة التي تم تمريرها في ، مما يتيح وسيلة مريحة تجمع أنواع.
وتستخدم كتل من العديد من الأساليب في روبي الطبقات ، فهي تستخدم فيها في PHP يمكنك استخدام رد الاتصال.
[1,2,3,4,5].each {|i| print "#{i} "}
[1,2,3,4,5].each do |i|
print "#{i} "
end
File.open('p014constructs.rb', 'r') do |f1|
while line = f1.gets
puts line
end
end
PHP5 قدم مجهول المهام ؛ بدلا من استخدام الاستدعاء ، يمكنك استخدام وظيفة مجهول.
echo preg_replace_callback('~-([a-z])~', function ($match) {
return strtoupper($match[1]);
}, 'hello-world');
Procs, المعروف أيضا باسم الإغلاق أو lambdas هو مفهوم في روبي التي قد تبدو مربكة في البداية خاصة إلى مبتدئ.باختصار ، procs تسمح لك لتمرير قانون الكتل مع سهولة.مثال أدناه
hello = Proc.new do |x, y|
puts "i am a proc"
sum = x+y
puts "sum: #{sum}"
end
الآن للاستفادة من هذا كتلة من التعليمات البرمجية فقط استدعاء الأسلوب "الدعوة" على مرحبا.نلاحظ أن المثال أعلاه يتلقى الحجج x و y التي كتلة التعليمات البرمجية يستخدم.لذلك تأكد من أن تمر في الحجج عند استدعاء من بروك كائن مثل فعلت أدناه:
hello.call(2, 3)
مما أسفر عن النتائج التالية:
i am a proc
sum: 5
يا هلا!!هذا هو وسيلة سهلة لإنشاء مجلد الكائن.كيف مفيدة هو هذا ؟ حسنا, proc الكائنات تسمح لك لتمرير حول أجزاء من التعليمات البرمجية.الرسم التوضيحي أدناه يوضح ذلك بشكل أفضل من خلال الاستفادة من بروك بإنشائه في المثال أعلاه.دعونا خلق عشوائي الصف ،
class SomeClass
def initialize(&block)
@block = block
end
def output_value(x, y)
@block.call(x, y)
end
end
الآن, دعونا إنشاء مثيل SomeClass,
some_class = SomeClass.new(&hello)
علما بأن العطف علامة "&" قبل مرحبا يسمح لك لتمرير proc كائن كحجة.
وأخيرا دعونا إخراج القيمة عن طريق تمرير 2 الحجج ، مثل أدناه:
some_class.output_value(1, 3)
النتيجة التي تحصل هي على النحو التالي:
i am a proc
sum: 4
انظر!!الامر بهذه البساطة.كنت قادرا على تمرير قطعة من التعليمات البرمجية في جميع أنحاء.Procs مفيدة جدا أن روبي يجعل استخدام من ذلك كثيرا.نأمل أن يكون هذا السوبر مفيدة :)
هذه المفاهيم ترتبط المفاهيم من البرمجة الوظيفية في روبي ، وبالتالي فإنه يتيح لك استخدام أنماط والتقنيات التي عادة ما تكون موجودة في اللغات ، حيث الوظائف مواطنين من الدرجة الأولى.
كتل procs تمكنك من استخراج قطع صغيرة من التعليمات البرمجية دون الحمل الكامل و تعقيد أساليب.
حتى map
في حد ذاته هو قوي جدا و مسج بنيت حول هذا المفهوم نفسه:
['spite','rest','purpose'].map {|s| s << 'ful' }
و يمكنك رمي المنطق في إذا لزم الأمر
['sprite','restful','luck'].map {|s| s << (s.end_with?('uck') ? 'i' : '') << 'ly' }
هناك ذكية المشغل '&' الذي يعني "تحويل الرمز إلى مجلد و نسميه" ، حتى تتمكن من تحويل الأجسام السلاسل:
['spite',12,:purpose].map(&:to_s)
واستخدام الإغلاق و بين الكتابة بسيط الإغلاق يمكن أن نجد أين المجاورة من الأرقام تظهر.هذا هو الخرقاء بدلا روبي, ولكن أكثر إيجازا من معظم اللغات:
last = -2 # this variable is accessed and changed within the closure
objs.sort.map do |o|
if (last + 1) != o
last = o
nil # not one more than previous so return nil
else
o
end
end.compact # compact removes nils
عند بدء كتابة في لغة أخرى كنت أدرك كم هو سهل.وهو يشجعك على بنية التعليمات البرمجية الخاصة بك في العمليات الصغيرة ، لذلك هو أكثر يمكن إعادة استخدامها و قابلة للاختبار.