الدوال في Swift: التسميات والمغلقات Closures
الدوال في Swift لها طابع خاص يجعل الكود يُقرأ كجملة إنجليزية: greet(person: "سارة") و move(from: start, to: end). هذا بفضل ميزة اسمها تسميات المعاملات (Argument Labels). في هذا الدرس ستكتب دوالك، وتتعلم هذه الميزة، ثم تتعرف على المغلقات (Closures) التي ستراها في كل مكان في SwiftUI.
تعريف دالة
Section titled “تعريف دالة”func greet() { print("أهلاً بك في Swift!")}
func add(a: Int, b: Int) -> Int { return a + b}
greet()print(add(a: 3, b: 4))أهلاً بك في Swift!7func: كلمة تعريف الدالة.(a: Int, b: Int): المعاملات وأنواعها.-> Int: السهم ثم نوع القيمة المرجعة. الدالة التي لا تُرجع شيئاً لا تحتاج سهماً.- عند الاستدعاء تكتب أسماء المعاملات:
add(a: 3, b: 4).
وإذا كان جسم الدالة تعبيراً واحداً، يمكنك حذف return:
func square(_ x: Int) -> Int { x * x}تسميات المعاملات
Section titled “تسميات المعاملات”كل معامل في Swift له اسمان محتملان:
- التسمية الخارجية (Argument Label): تُكتب عند الاستدعاء.
- الاسم الداخلي (Parameter Name): يُستخدم داخل الدالة.
func greet(person name: String) -> String { "أهلاً يا \(name)"}
print(greet(person: "سارة"))أهلاً يا سارةperson تسمية خارجية تجعل الاستدعاء مقروءاً: greet(person: "سارة")، و name اسم داخلي واضح داخل الدالة.
وإذا كانت التسمية لا تضيف وضوحاً، أخفِها بالشرطة السفلية _:
print(square(5))25بفضل _ في func square(_ x: Int) نكتب square(5) بدلاً من square(x: 5).
تخيّل التسميات مثل الأزرار المكتوب عليها في جهاز التحكم: «رفع الصوت» أوضح بكثير من زر بلا كتابة. لكن زر «تشغيل» واضح من شكله، فلا يحتاج كتابة.
القيم الافتراضية
Section titled “القيم الافتراضية”func makeTea(sugar: Int = 2) -> String { "شاي بـ \(sugar) ملاعق سكر"}
print(makeTea())print(makeTea(sugar: 0))شاي بـ 2 ملاعق سكرشاي بـ 0 ملاعق سكرinout: تعديل المتغير الأصلي
Section titled “inout: تعديل المتغير الأصلي”المعاملات في Swift ثوابت داخل الدالة، فلا يمكن تغييرها. وإذا أردت أن تعدّل الدالة متغيراً من خارجها، استخدم inout، وضع & قبل المتغير عند الاستدعاء:
func addPoints(_ score: inout Int, bonus: Int) { score += bonus}
var myScore = 10addPoints(&myScore, bonus: 5)print(myScore)15العلامة & تُذكّر كل من يقرأ الكود أن هذا المتغير قد يتغير داخل الدالة. لكن الأسلوب المفضل غالباً أن تُرجع الدالة القيمة الجديدة بدلاً من inout.
المغلقات (Closures)
Section titled “المغلقات (Closures)”المغلق دالة بلا اسم، تكتبها مباشرة بين قوسين معقوفين وتمررها كقيمة:
let double = { (x: Int) -> Int in x * 2}print(double(21))42الكلمة in تفصل بين المعاملات والجسم. وأجمل استخدام للمغلقات مع المصفوفات:
let numbers = [1, 2, 3]let doubled = numbers.map { $0 * 2 }print(doubled)[2, 4, 6]map: تطبق المغلق على كل عنصر وتُرجع مصفوفة جديدة.$0: اختصار لـ المعامل الأول في المغلق، فلا تحتاج تسميته.- عندما يكون المغلق آخر معامل، يُكتب خارج القوسين، ويسمى Trailing Closure.
تبدو مختصرة جداً، لكنها مألوفة بسرعة. ولهذا الأسلوب أهمية كبيرة: واجهات SwiftUI كلها مبنية بالمغلقات، مثل:
Button("اضغط هنا") { print("تم الضغط")}المغلق بعد Button(...) هو الكود الذي يُنفَّذ عند الضغط.
جرّب بنفسك
Section titled “جرّب بنفسك”func priceAfterDiscount(_ price: Double, percent: Double = 10) -> Double { price - price * percent / 100}
print(priceAfterDiscount(200))print(priceAfterDiscount(200, percent: 25))180.0150.0تحدٍّ: اكتب دالة grade(for score: Int) -> String تستخدم switch بالمجالات، ثم استخدم map لتحويل مصفوفة درجات إلى مصفوفة تقديرات.
أخطاء شائعة
Section titled “أخطاء شائعة”- نسيان التسمية عند الاستدعاء:
add(3, 4)خطأ إذا كانت الدالةadd(a:b:). اكتبadd(a: 3, b: 4)، أو استخدم_في التعريف. - محاولة تغيير معامل داخل الدالة: المعاملات ثوابت. انسخها في
var، أو استخدمinout. - نسيان & مع inout: خطأ ترجمة يطلب منك إضافتها.
اختبر نفسك
Section titled “اختبر نفسك”سؤال
كيف تستدعي الدالة func move(from start: Int, to end: Int)؟
عند الاستدعاء تُستخدم التسميات الخارجية from و to، أما start و end فأسماء داخلية.
سؤال
ماذا يعني $0 داخل المغلق numbers.map { $0 + 1 }؟
$0 اختصار للمعامل الأول، وهو هنا كل عنصر من عناصر المصفوفة بالدور.
الخلاصة
Section titled “الخلاصة”func name(param: Type) -> ReturnType، وجسم التعبير الواحد لا يحتاجreturn.- التسميات الخارجية تجعل الاستدعاء كجملة مقروءة، و
_تخفيها. - القيم الافتراضية للمعاملات، و
inoutمع&لتعديل المتغير الأصلي. - المغلقات دوال بلا اسم
{ (x) -> T in ... }، و$0اختصار للمعامل الأول. - المغلق الأخير يُكتب خارج القوسين، وهذا أساس كود SwiftUI.