الإغلاقات في Swift هي كتل من الكود مكتفية بذاتها، ويمكن تمرير معاملات إليها لتحفيز حساباتها وإرجاع قيم. كما تلتقط الإغلاقات قيمًا من بيئتها وتستخدمها في حساباتها. ولأنها مكتفية بذاتها، يمكن تمريرها في البرنامج مثل القيم الأخرى أو إسنادها إلى ثوابت ومتغيرات.
قد تبدو الإغلاقات شبيهة كثيرًا بدوال Swift؛ وهي كذلك، ولسبب وجيه. الدوال في Swift هي حالات خاصة من الإغلاقات، وهي مطلوبة أن يكون لها اسم وتُعرَّف باستخدام صياغة مختلفة قليلًا.
بينما الدوال في Swift هي إغلاقات من الناحية التقنية، عندما يشير الناس إلى "الإغلاقات" في Swift، فإنهم يشيرون إلى تعبيرات الإغلاق. تُكتب تعبيرات الإغلاق على هيئة قائمة معاملات يتبعها نوع الإرجاع والكلمة المفتاحية in يتبعها جسم الإغلاق، وكل ذلك داخل زوج من الأقواس المعقوفة:
{ (a: Double, b: Double) -> Double in
return (a + b) / 2.0
}
هذا يُعرّف تعبير إغلاق من النوع (Double, Double) -> Double، ويمكن تنفيذه بطريقة مشابهة لدالة من هذا النوع، بتطبيقه على معاملات من النوع المناسب:
{ (a: Double, b: Double) -> Double in
return (a + b) / 2.0
}(10.0, 15.0)
// returns 12.5
بما أنه ليس من المريح كتابة تعبير الإغلاق الكامل في كل مرة يريد المرء تنفيذه، يمكن إسناد الإغلاقات إلى أسماء، مثل أي قيمة أخرى في Swift. ثم يمكن استدعاؤها بتطبيق الاسم على المعاملات:
let mean = { (a: Double, b: Double) -> Double in
(a + b) / 2.0
}
mean(13.0, 100.0)
// returns 56.5
كما رأينا أعلاه، يمكن للإغلاقات، مثل الدوال العادية، أن تحذف الكلمة المفتاحية return إذا كان جسم الإغلاق تعبيرًا واحدًا.
في أغلب الأحيان، تُستخدم الإغلاقات مع الدوال ذات الرتبة الأعلى، إما بتمريرها كمعاملات أو إرجاعها كنتائج:
[11, 75, 3, 99, 53].contains(where: { (x: Int) -> Bool in x > 100 })
// returns false
["apple", "ball", "carrot"].sorted(by: { (s1: String, s2: String) -> Bool in s1.count < s2.count })
// returns ["ball", "apple", "carrot"]
func makeAdder(base: Int) -> (Int) -> Int {
{ (x: Int) -> Int in base + x }
}
مرحبًا مجددًا، أيها العميل Double-Null0111.
تعود قوى UMBRA إلى التحرك من جديد، وعليك أنت أن تُحبط مخططهم الأخير. يُبلغنا فرع الاستخبارات لدينا أن هؤلاء الـ Minions يخططون لتفجير قنبلة نتنة في الحفل الراقص للحاكم.
ولأن الـ minions خرقاء جدًا، فإنهم كثيرًا ما يُسلّحون القنابل النتنة بالخطأ في مختبراتهم ومكاتبهم. ولأنهم ينسون باستمرار كيفية إبطال قنابلهم النتنة، فقد أنشأوا نظامًا يُولّد تعليمات الإبطال التي تسرد الترتيب الذي يجب قطع الأسلاك به انطلاقًا من رقم تعريف القنبلة.
مهمتك هي كتابة الكود الذي سيتيح لك إبطال القنبلة النتنة في الحفل قبل أن تنفجر.
توجد ثلاثة أسلاك مختلفة الألوان على كل قنبلة نتنة.
اكتب إغلاقًا يأخذ صفًا من النوع (String, String, String) ويُرجع الصف بعد قلب ترتيب العنصرين الأولين.
أسنِد هذا الإغلاق إلى الاسم flip.
من المهم ملاحظة أن النوع يجب أن يكون ChangeClosure (أو نوعًا قابلًا للإرسال)، وتعريف النوع موجود في ملف البداية.
وإلا فلن يُترجم الكود.
flip(("red", "yellow", "blue"))
// Returns ("yellow", "red", "blue")
اكتب إغلاقًا يأخذ صفًا من النوع (String, String, String) ويُرجع الصف بعد تدوير ترتيب الأسلاك إلى اليسار.
أسنِد هذا الإغلاق إلى الاسم rotate.
من المهم ملاحظة أن النوع يجب أن يكون ChangeClosure (أو نوعًا قابلًا للإرسال)، وتعريف النوع موجود في ملف البداية.
rotate(("red", "yellow", "blue"))
// Returns ("yellow", "blue", "red")
لكي تعرف الترتيب الذي يجب قطع أسلاك القنبلة النتنة به، ستحتاج إلى تنفيذ دالة تُولّد دالة الخلط المناسبة بناءً على رقم تعريف القنبلة النتنة.
نفّذ الدالة:
makeShuffle(
flipper: @escaping ((String, String, String)) -> (String, String, String),
rotator: @escaping ((String, String, String)) -> (String, String, String)
) -> ([UInt8], (String, String, String)) -> (String, String, String)
وهي تأخذ كمدخل إغلاقًا يقلب سلكين وإغلاقًا يدوّر الأسلاك الثلاثة، وتُرجع إغلاقًا. هذا الإغلاق المُرجَع يأخذ رقم تعريف القنبلة النتنة وترتيب الأسلاك الثلاثة، ثم يحسب الترتيب الذي يجب قطع الأسلاك به. يتكوّن رقم المعرّف من ثمانية بتات، ويحدد كل بت ما إذا كان يجب قلب الأسلاك أو تدويرها.
لكل بت في رقم المعرّف، بدءًا من البت الواقع في أقصى اليمين، ستطبّق إغلاق flipper على صف الأسلاك إذا كانت قيمة البت 0، وستطبّق إغلاق rotator إذا كانت قيمته 1، ما يمنح الحالة الجديدة للأسلاك.
بعد تطبيق الإغلاقات المناسبة على البتات الثمانية في المعرّف، تكون الحالة النهائية للأسلاك هي الترتيب الذي يجب قطعها به.
let shuffler = makeShuffle(flipper: flip, rotator: rotate)
// Returns ([UInt8], (String, String, String)) -> (String, String, String)
shuffler([1, 0, 0, 1, 1, 0, 1, 1], ("red", "yellow", "blue"))
// Returns ("red", "blue", "yellow")
سجّل في Exercism لتتعلّم وتتقن Swift عبر 35 مفهومًا116 تمرينًا، وإرشاد بشري حقيقي، وكل ذلك مجانًا.