() translation by (you can also view the original English article)
في المقالة السابقة ، استكشفنا أساسيات الوظائف في Swift. غ في هذه المقالة ، سنواصل استكشافنا للوظائف وننظر في معلمات الوظائف ، والتداخل ، والأنواع.
1. أسماء المعلمات المحلية والخارجية
أسماء المعلمات المحلية
دعنا نرجع إلى أحد الأمثلة على المقالة السابقة. ن
1 |
func printMessage(message: String) { |
2 |
println(message) |
3 |
}
|
على الرغم من أننا نعطي المعلمة اسماً أو رسالة
، إلا أننا لا نستخدم الاسم عندما نسمي الوظيفة. نحن نمرر قيمة معلمة الرسالة
.
1 |
printMessage("Hello, world!") |
الاسم الذي نحدده في تعريف الدالة هو اسم معلمة محلي . لا يمكن الرجوع إلى قيمة المعلمة إلا بهذا الاسم في نص الدالة. ومع ذلك ، فإن معلمات الدالة أكثر مرونة قليلاً من ذلك. اسمحوا لي أن أشرح ما أعنيه بذلك.
يُعرف Objective-C بأسماء الأساليب الطويلة الخاصة به. في حين أن هذا قد يبدو مضجرًا وغير متماسك تجاه الغرباء ، إلا أنه يجعل الطرق سهلة الفهم ، وإذا تم اختياره بشكل جيد ، فسيكون وصفيًا للغاية. إذا كنت تعتقد أنك فقدت هذه الميزة عند التبديل إلى Swift ، فأنت في مفاجأة.
أسماء المعلمات الخارجية
ت ألق نظرة على المثال التالي لفهم المشكلة بشكل أفضل .
1 |
func power(a: Int, b: Int) -> Int { |
2 |
var result = a |
3 |
|
4 |
for _ in 1..<b { |
5 |
result = result * a |
6 |
}
|
7 |
|
8 |
return result |
9 |
}
|
على السلطة
وظيفة ترفع قيمة من
قبل الأس ب
. خ خ كما رأينا في المقالة السابقة ، فإن استدعاء الوظيفة واضح.
1 |
power(2, 3) |
لتجنب الارتباك ، يمكننا إعطاء المعلمات لأسماء خارجية وظيفة. خ ألق نظرة على المثال المحدث أدناه.
1 |
func power(base a: Int, exponent b: Int) -> Int { |
2 |
var result = a |
3 |
|
4 |
for _ in 1..<b { |
5 |
result = result * a |
6 |
}
|
7 |
|
8 |
return result |
9 |
}
|
لاحظ أن جسم الدالة لم يتغير منذ أن لم تتغير الأسماء المحلية. ومع ذلك ، عندما نستدعي الوظيفة المحدثة ، يكون الفرق واضحًا وتكون النتيجة أقل إرباكًا.
1 |
power(base: 2, exponent: 3) |
في حين أن أنواع كلتا الوظيفتين هي نفسها ، (Int ، Int) -> Int
، فإن الوظائف مختلفة. وبعبارة أخرى ، فإن الوظيفة الثانية ليست إعادة تعريف للوظيفة الأولى. قد تذكر جملة استدعاء الدالة الثانية بعضًا من Objective-C. ليس فقط هي الحجج التي تم وصفها بوضوح ، فإن الجمع بين الدالة وأسماء المعلمات تصف الغرض من الوظيفة.
في بعض الحالات ، تريد استخدام نفس الأسماء لأسماء المعلمات المحلية والخارجية. هذا ممكن وليس هناك حاجة لكتابة اسم المعلمة مرتين. في المثال التالي، ونحن نستخدم قاعدة
والأس
مثل أسماء المعلمات المحلية والخارجية.
1 |
func power(#base: Int, #exponent: Int) -> Int { |
2 |
var result = base |
3 |
|
4 |
for _ in 1..<exponent { |
5 |
result = result * base |
6 |
}
|
7 |
|
8 |
return result |
9 |
}
|
من خلال بادئة اسم المعلمة برمز #
، يكون اسم المعلمة بمثابة الاسم المحلي والخارجي للمعلمة. هذا يعني أيضا أننا بحاجة إلى تحديث جسم الوظيفة.
من المهم ملاحظة أنه من خلال توفير اسم خارجي للمعلمة ، يجب عليك استخدام هذا الاسم عند استدعاء الوظيفة. هذا يقودنا إلى القيم الافتراضية.
قيم افتراضية
لقد غطينا قيم المعلمات الافتراضية في المقالة السابقة ، ولكن هناك سلوك افتراضي مهم يجب أن تكون على دراية به. إذا قمت بتحديد قيمة افتراضية للمعلمة ، يقوم Swift تلقائيًا بتعيين اسم معلمة خارجي للمعلمة. دعونا ننظر إلى مثال على المادة السابقة .
1 |
func printDate(date: NSDate, format: String = "YY/MM/dd") -> String { |
2 |
let dateFormatter = NSDateFormatter() |
3 |
dateFormatter.dateFormat = format |
4 |
return dateFormatter.stringFromDate(date) |
5 |
}
|
لأن المعلمة الثانية، شكل
، له قيمة افتراضية، سويفت تلقائيا تعيين اسم المعلمة الخارجي منشكل
إلى شكل
. وبعبارة أخرى، فإن النتيجة هي نفسها كما لو كنا بادئةالتنسيق
مع #
رمز. يمكنك اختبار ذلك عن طريق استدعاء الوظيفة المذكورة أعلاه في الملعب الخاص بك. ع الجواب مبين أدناه.



سويفت هو واضح جدا حول ما يجب علينا القيام به. للتلخيص ، عندما تحدد معلمة اختيارية ، يقوم Swift تلقائيًا بتعيين اسم المعلمة الخارجية إلى اسم المعلمة المحلية. الفكرة وراء هذا السلوك هو تجنب الارتباك والغموض.
في حين أن هذا السلوك هو أفضل الممارسات الجيدة ، فمن الممكن تعطيله. في تعريف الدالة المحدّث أدناه ، نضيف تسطير سفلي حيث سنقوم عادةً بإضافة اسم المعلمة الخارجية. يخبرنا ذلك Swift أننا لا نريد تعيين اسم معلمة خارجي لتلك المعلمة الخاصة ، على الرغم من وجود قيمة افتراضية.
1 |
func formatDate(date: NSDate, _ format: String = "YY/MM/dd") -> String { |
2 |
let dateFormatter = NSDateFormatter() |
3 |
dateFormatter.dateFormat = format |
4 |
return dateFormatter.stringFromDate(date) |
5 |
}
|
يمكننا الآن استدعاء دالة formatDate
بدون تقديم اسم للوسيطة الثانية.
1 |
formatDate(NSDate(), "dd/MM/YY") |
2. المعلمات و التغير
دعنا نرجع إلى المثال الأول من هذا البرنامج التعليمي ، وظيفة printMessage
. ماذا يحدث إذا قمنا بتغيير قيمة معلمة الرسالة
داخل جسم الدالة؟
1 |
func printMessage(message: String) { |
2 |
message = "Print: \(message)" |
3 |
println(message) |
4 |
}
|
لا يستغرق الأمر وقتًا طويلاً حتى يبدأ Swift في الشكوى.



بشكل افتراضي ، تكون معلمات الدالة ثوابت. بمعنى آخر ، بينما يمكننا الوصول إلى قيم معلمات الوظيفة ، لا يمكننا تغيير قيمتها. لتغيير هذا السلوك الافتراضي ، قم بإضافة الكلمة الأساسية var
إلى اسم المعلمة في تعريف الدالة. سيقوم Swift بإنشاء نسخة متغيرة من قيمة المعلمة لكي تعمل مع نص الدالة.
1 |
func printMessage(var message: String) { |
2 |
message = "Print: \(message)" |
3 |
println(message) |
4 |
}
|
لاحظ أن هذا لا يعني أنه يمكنك تمرير قيمة وتعديلها في الدالة واستخدام القيمة المعدلة بعد أن تقوم الوظيفة بعملها. يقوم Swift بإنشاء نسخة من قيمة المعلمة الموجودة فقط طوال مدة استدعاء الدالة. هذا موضح أيضًا في مقطع التعليمات البرمجية التالي الذي يتم تمرير ثابت إلى الدالة printMessage
.
1 |
func printMessage(var message: String) { |
2 |
message = "Print: \(message)" |
3 |
println(message) |
4 |
}
|
5 |
|
6 |
let myMessage = "test" |
7 |
|
8 |
printMessage(myMessage) |
3. معلمات Variadic
على الرغم من أن المصطلح قد يبدو غريباً في البداية ، إلا أن المعلمات المتنوعة شائعة في البرمجة. المعلمة variadic هي معلمة تقبل قيم صفرية أو أكثر. يجب أن تكون القيم من نفس النوع. يعد استخدام المعلمات المتغيرة في Swift تافها كما يوضح المثال التالي.
1 |
func sum(args: Int...) -> Int { |
2 |
var result = 0 |
3 |
|
4 |
for a in args { |
5 |
result += a |
6 |
}
|
7 |
|
8 |
return result |
9 |
}
|
بناء الجملة من السهل فهمه. ت في جسم الوظيفة ، يمكن الوصول إلى المعلمة variadic كمصفوفة. في المثال أعلاه ، args
عبارة عن صفيف من قيم Int
.
لأن Swift يحتاج إلى معرفة أي من الوسيطات تتوافق مع أي من المعلمات ، يجب أن تكون المعلمة variadic هي المعلمة الأخيرة. ويعني أيضاً أن الوظيفة يمكن أن تحتوي على معلمة متغيرة واحدة على الأكثر.
ينطبق ما سبق أيضًا إذا كانت إحدى الدوال تحتوي على معلمات لها قيم افتراضية. يجب أن تكون المعلمة variadic دومًا المعلمة الأخيرة.
4. داخل-- خارج المعلمات
في وقت سابق من هذا البرنامج التعليمي ، تعلمت كيف يمكنك تعريف قابلية المعلمة باستخدام الكلمة الرئيسية var
. في هذا القسم ، أكدت على أنه لا يمكن الوصول إلى قيمة المعلمة المتغيرة إلا من داخل جسم الوظيفة. إذا كنت ترغب في تمرير قيمة إلى إحدى الوظائف ، فعدّلها في الدالة ، وأخرجها من الوظيفة ، فالمعلمات الداخلية هي ما تبحث عنه.
يوضح المثال التالي مثالاً لكيفية عمل معلمات In-out في Swift وما يبدو عليه بناء الجملة.
1 |
func prependString(inout a: String, withString b: String) { |
2 |
a = b + a |
3 |
}
|
لقد حددنا المعلمة الأولى كمعلمة داخلية من خلال إضافة الكلمة الرئيسية الناقصة
. المعلمة الثانية هي معلمة عادية تحمل اسمًا خارجيًا باسم withString
واسم محلي لـ b
. دعونا نرى كيف نستدعي هذه الوظيفة.
1 |
var world = "world" |
2 |
|
3 |
prependString(&world, withString: "Hello, ") |
نعلن متغير، عالم
، من نوع سلسلة
وتمريرها إلى perpendString
وظيفة. المعلمة الثانية هي سلسلة حرفية. من خلال استدعاء الدالة ، تصبح قيمة متغير العالم
Hello، world
. لاحظ أن الوسيطة الأولى مسبوقة بعلامة العطف ، &
، للإشارة إلى أنها معلمة In-out.
وغني عن القول أن الثوابت والحروف لا يمكن تمريرها كمعلمات داخلية. سوف يلقي Swift خطأ عندما تفعل كما هو موضح في الصورة التالية.



من الواضح أن المعلمات الداخلية لا يمكن أن تحتوي على قيم افتراضية ، أو تكون متغايرة ، أو يمكن تعريفها على أنها var
أو let
. إذا نسيت هذه التفاصيل ، فسيتذكرك Swift بخطأ ما.
5. التعشيش
في C و Objective-C ، لا يمكن تداخل الوظائف والأساليب. في سويفت ، ومع ذلك ، وظائف متداخلة شائعة جدا. الوظائف التي رأيناها في هذا المقال والمادة السابقة هي أمثلة على الوظائف العالمية ، وهي محددة في النطاق العالمي.
عندما نحدد وظيفة داخل دالة عالمية ، فإننا نشير إلى هذه الوظيفة كدالة متداخلة. تتمتع الوظيفة المتداخلة بالوصول إلى القيم المحددة في دالة الإحاطة الخاصة بها . ألق نظرة على المثال التالي لفهم هذا بشكل أفضل.
1 |
func printMessage(message: String) { |
2 |
let a = "hello world" |
3 |
|
4 |
func printHelloWorld() { |
5 |
println(a) |
6 |
}
|
7 |
}
|
في حين أن الوظائف في هذا المثال ليست مفيدة بشكل فاضح ، يوضح المثال فكرة الدالة المتداخلة وقيم الالتقاط. و printHelloWorld
وظيفة يمكن الوصول إليها إلا من داخلprintMessage
وظيفة. كما هو موضح في المثال ، تتمتع وظيفة printHelloWorld
بالوصول إلى الثابت a
. يتم التقاط القيمة بواسطة الدالة المتداخلة ومن ثم يمكن الوصول إليها من داخل هذه الوظيفة. يعتني Swift بالتقاط القيم ، بما في ذلك إدارة ذاكرة تلك القيم .
6. أنواع الوظيفة
في المقالة السابقة ، تطرقنا باختصار إلى أنواع الوظائف. تحتوي الدالة على نوع معين ، يتألف من أنواع المعلمات الخاصة بالوظيفة ونوع الإرجاع الخاص بها. وprintMessage
وظيفة، على سبيل المثال، من نوع (سلسلة) -> ()
. تذكر أن ()
يرمز إلى Void
، وهو ما يعادل مجموع فارغ.
نظرًا لأن لكل وظيفة نوعًا ما ، فمن الممكن تحديد دالة تقبل وظيفة أخرى كمعلمة . يوضح المثال التالي كيفية عمل ذلك.
1 |
func printMessageWithFunction(message: String, printFunction: (String) -> ()) { |
2 |
printFunction(message) |
3 |
}
|
4 |
|
5 |
let myMessage = "Hello, world!" |
6 |
|
7 |
printMessageWithFunction(myMessage, printMessage) |
و printMessageWithFunction
وظيفة تقبل سلسلة كمعلمة أولى وظيفة من نوع (سلسلة) -> ()
كمعلمة الثانية. في جسم الدالة ، يتم استدعاء الدالة التي نمررها باستخدام وسيطة الرسالة
.
يوضح المثال أيضًا كيف يمكن استدعاء دالةprintMessageWithFunction
. و myMessage
يتم تمرير ثابت في كوسيطة الأولى و printMessage
وظيفة، وهو ما يعرف في وقت سابق، كما الوسيطة الثانية. كم ذلك رائع؟
كما ذكرت سابقًا ، من الممكن أيضًا إرجاع وظيفة من إحدى الوظائف. المثال التالي هو مفتعل قليلاً ، ولكنه يوضح كيف تبدو البنية.
1 |
func compute(addition: Bool) -> (Int, Int) -> Int { |
2 |
func add(a: Int, b: Int) -> Int { |
3 |
return a + b |
4 |
}
|
5 |
|
6 |
func subtract(a: Int, b: Int) -> Int { |
7 |
return a - b |
8 |
}
|
9 |
|
10 |
if addition { |
11 |
return add |
12 |
} else { |
13 |
return subtract |
14 |
}
|
15 |
}
|
16 |
|
17 |
let computeFunction = compute(true) |
18 |
let result = computeFunction(1, 2) |
19 |
println(result) |
على حساب
وظيفة تقبل منطقي وإرجاع وظيفة من نوع (الباحث، الباحث) -> كثافة العمليات
. على حساب
يحتوي على وظيفة وظيفتين المتداخلة التي هي أيضا من نوع (الباحث، الباحث) -> كثافة العمليات
، إضافة
و طرح
.
ل حساب
الدالة بإرجاع إشارة إلى إما إضافة
أو إطرح
ظيفة، استنادا إلى قيمةبالإضافة
المعلمة. يوضح المثال أيضًا كيفية استخدام وظيفة الحساب
. نقوم بتخزين مرجع إلى الدالة التي يتم إرجاعها بواسطة دالة حساب
في ثابتcomputeFunction
. ثم نستدعي الدالة المخزنة فيcomputeFunction
، تمر في 1
و 2
، وتخزين النتيجة في النتيجة
، وطباعة قيمة النتيجة
في الإخراج القياسي. قد يبدو المثال معقدًا ، ولكن من السهل فهمه إذا كنت تعرف ما يحدث.
استنتاج
يجب أن يكون لديك الآن فهم جيد لكيفية عمل الوظائف في Swift وما يمكنك القيام به معهم. وظائف هي موضوع مشترك في سويفت وسوف تستخدمها على نطاق واسع عند العمل مع سويفت.
في المقالة التالية ، نغوص رأسًا أولاً في الإغلاق ، وهو بناء قوي يذكرنا جدًا بالكتل في C و Objective-C ، والإغلاق في JavaScript ، و lambdas في Ruby.