يمكن تزويد أيٍّ من معاملات الدالة بـقيم افتراضية للمعاملات عبر إسناد قيمة إلى المعامل في قائمة المعاملات بعد تعليق النوع الخاص بالمعامل. وعند تحديد قيمة افتراضية لمعامل ما، يستطيع من يستدعي الدالة أن يحذف ذلك المعامل عند استدعاء الدالة، وستُستخدم القيمة الافتراضية بدلًا منه.
func greeting(name: String = "guest", duration: Int = 2) -> String {
"Welcome, \(name). Enjoy your \(duration) night stay."
}
greeting(name: "Bobo", duration: 7)
// Returns "Welcome, Bobo. Enjoy your 7 night stay."
greeting(duration: 3)
// Returns "Welcome, guest. Enjoy your 3 night stay."
greeting(name: "Wynona")
// Returns "Welcome, Wynona. Enjoy your 2 night stay."
greeting()
// Returns "Welcome, guest. Enjoy your 2 night stay."
تسمح المعاملات المتغيرة العدد للدالة بقبول صفر أو أكثر من القيم من نوع محدد في معامل واحد.
وتُعرّف المعامل المتغير العدد بإضافة ثلاث نقاط (...) إلى تعليق النوع الخاص بالمعامل.
وداخل جسم الدالة، يجعل Swift هذه القيم متاحة على هيئة مصفوفة من النوع المحدد:
import Foundation
func geometricMean(_ numbers: Double...) -> Double {
var total = 1.0
for number in numbers {
total *= number
}
return pow(total, 1.0 / Double(numbers.count))
}
let result = geometricMean(1, 2, 3, 4, 5)
// result is 2.605171084697352
إذا تضمنت الدالة معاملات إضافية بعد معامل متغير العدد، فالمعامل الأول بعد المعامل المتغير العدد يجب أن يحمل وسم وسيط صريح، حتى يعرف Swift أين تنتهي قائمة الوسائط المتغيرة العدد.
داخل جسم الدالة، تُعامَل المعاملات على أنها ثوابت لا متغيرات؛ ومحاولة تعديل قيمة معامل ما ستُثير خطأً في وقت الترجمة. وإذا أرادت الدالة تعديل قيمة معامل، فعليها استخدام معامل دخل وخرج لجعل قابلية التغيير هذه صريحة.
لاستخدام معاملات الدخل والخرج، على المبرمج أن يتأكد من ثلاثة أمور:
inout بين : واسم النوع في تعليق النوع الخاص بالمعامل.& في استدعاء الدالة، لتحديد أنه قابل للتعديل صراحةً.وعند القيام بذلك، ستُنشئ الدالة نسخة داخلية من معامل الدخل والخرج، وتعدّلها كما هو مطلوب في جسم الدالة، ثم تنسخ القيمة المعدّلة مرة أخرى إلى المتغير الذي مُرِّر عند رجوع الدالة.
func updateVersion(_ record: inout (version: Int, title: String)) {
record.version += 1
}
var dbRecord = (version: 2, title: "Exercism")
updateVersion(&dbRecord)
// dbRecord is now (3, "Exercism")
هناك قاعدتان إضافيتان ينبغي الانتباه إليهما فيما يخص معاملات الدخل والخرج.
1 داخل دالة لها معاملات دخل وخرج، لا يُسمح لك بالإشارة إلى المتغير الذي مُرِّر كمعامل دخل وخرج.
2. لا يمكن تمرير المتغير نفسه كعدة معاملات دخل وخرج في الدالة نفسها.
فعلى سبيل المثال، يؤدي `inoutFunc(&mutVar, &mutVar)` إلى خطأ في المترجم.
في Swift، يمكنك تعريف دوال داخل دوال أخرى. وتُعرف هذه بـالدوال المتداخلة.
ويُستخدم هذا النوع من الدوال عادةً كدوال مساعدة خاصة تؤدي مهام محددة للدالة الحاوية دون إثقال النطاق الخارجي:
func makeNumber(_ number: Int) -> Int {
func double(_ x: Int) -> Int {
x * 2
}
func increment(_ x: Int) -> Int {
x + 1
}
return number.isMultiple(of: 2) ? increment(double(number)) : double(number)
}
print(makeNumber(3)) // Prints 6
print(makeNumber(4)) // Prints 9
تتصرف الدوال المتداخلة كالدوال العادية، لكن رؤيتها مقصورة على جسم الدالة الحاوية.
في هذا التمرين ستكتب المزيد من الكود لمساعدتك على طهي اللازانيا الرائعة من كتاب الطهي المفضل لديك.
لديك خمس مهام، وكلها مرتبطة بالوقت الذي تقضيه في طهي اللازانيا.
تريد كتابة دالة remainingMinutesInOven محسّنة تأخذ عدد الدقائق المنقضية التي قضتها اللازانيا في الفرن كمعامل، وتُرجع عدد الدقائق التي ما زالت اللازانيا بحاجة إلى قضائها في الفرن، بناءً على وقت الفرن المتوقع بالدقائق من المهمة السابقة.
في السابق، كنت تعتمد على قيمة ثابتة هي expectedMinutesInOven تأتي من خارج دالة remainingMinutesInOven.
كان ذلك مزدحمًا أكثر قليلًا مما يناسب ذوقك، ولم يكن مرنًا بما يكفي، لأنه لا يسمح لك بتغيير الوقت المتوقع في الفرن.
لترتيب الأمور، عرّف دالة remainingMinutesInOven تأخذ عدد الدقائق المنقضية التي قضتها اللازانيا في الفرن كمعامل، إلى جانب معامل expectedMinutesInOven له قيمة افتراضية هي 40.
يجب أن تُرجع دالتك عدد الدقائق التي ما زالت اللازانيا بحاجة إلى قضائها في الفرن، بناءً على وقت الفرن المتوقع بالدقائق من المهمة السابقة.
remainingMinutesInOven(elapsedMinutes: 30)
// Returns 10
remainingMinutesInOven(elapsedMinutes: 30, expectedMinutesInOven: 75)
// Returns 45
كنت قد كتبت سابقًا دالة preparationTimeInMinutes تأخذ عدد الطبقات التي أضفتها إلى اللازانيا كمعامل، وتُرجع عدد الدقائق التي قضيتها في تحضير اللازانيا، بافتراض أن تحضير كل طبقة يستغرق دقيقتين.
لكنك لست راضيًا تمامًا عن هذه الدالة، لأن عليك أن تعدّ بنفسك عدد الطبقات في اللازانيا قبل أن تستطيع استدعاء هذه الدالة، ومن لديه وقت لكل هذا؟
لتسهيل الأمور عليك، اكتب دالة preparationTimeInMinutes تأخذ معاملًا متغير العدد من نوع String باسم layers، تُدرج فيه الطبقات المختلفة في اللازانيا.
ثم تعدّ الدالة عدد الطبقات في اللازانيا، وتُرجع مقدار وقت التحضير المطلوب.
preparationTimeInMinutes(layers: "sauce", "noodles")
// Returns 4
preparationTimeInMinutes(layers: "sauce", "noodles", "sauce", "meat", "mozzarella", "noodles", "sauce", "eggplant", "béchamel", "noodles", "sauce", "mozzarella")
// Returns 24
noodles و sauce
قبل أن تبدأ في تجميع اللازانيا، تريد التأكد من أن لديك ما يكفي من الصلصة والمعكرونة لبناء اللازانيا التي تحلم بها.
لكل طبقة noodles في اللازانيا، ستحتاج إلى 3 قطع من المعكرونة.
ولكل طبقة sauce في اللازانيا، ستحتاج إلى 0.2 لتر من الصلصة.
عرّف الدالة quantities التي تأخذ معاملًا متغير العدد من نوع String باسم layers، تُدرج فيه الطبقات المختلفة في اللازانيا.
ثم تحدد الدالة كمية المعكرونة والصلصة اللازمتين لتحضير وجبتك. ويجب إرجاع النتيجة في صف من النوع (noodles: Int, sauce: Double).
quantities(layers: "sauce", "noodles", "sauce", "meat", "mozzarella", "noodles", "sauce", "eggplant", "béchamel", "noodles", "sauce", "mozzarella")
// Returns (noodles: 9, sauce: 0.8)
quantities(layers: "sauce", "noodles", "sauce", "noodles", "meat", "noodles", "mozzarella")
// Returns (noodles: 9, sauce: 0.4)
لسوء الحظ، حجم الصلصة المتوفرة لديك مذكور بالأونصات السائلة بدلًا من اللترات.
لمساعدتك على معرفة ما إذا كان لديك ما يكفي من الصلصة، اكتب دالة toOz تأخذ معاملًا من نوع صف مدخل ومخرج، (noodles: Int, sauce: Double)، وتحوّل كمية الصلصة إلى أونصات سائلة.
لاحظ أن كل لتر يساوي 33.814 أونصة سائلة.
var amount = (noodles: 9, sauce: 0.8)
toOz(&amount)
amount
// Returns (noodles: 9, sauce: 27.0512)
أخيرًا، تريد معرفة نوع النبيذ الذي ينبغي تقديمه مع اللازانيا.
سمعت أنه ينبغي تقديم النبيذ الأبيض إذا كان في اللازانيا من mozzarella و ricotta و béchamel أكثر مما فيها من meat و sauce، وإلا فيُقدَّم النبيذ الأحمر.
اكتب دالة redWine تأخذ معاملًا متغير العدد من نوع String باسم layers، تُدرج فيه الطبقات المختلفة في اللازانيا.
ستستخدم الدالة خمس دوال متداخلة لتحديد عدد طبقات mozzarella و ricotta و béchamel و sauce و meat في اللازانيا، ثم تقارن أعداد الطبقات لتحديد ما إذا كان ينبغي تقديم النبيذ الأحمر، فتُرجع true إذا كان الأمر كذلك، و false إن لم يكن.
redWine(layers: "sauce", "noodles", "sauce", "meat", "mozzarella", "noodles", "sauce", "eggplant", "béchamel", "noodles", "sauce", "mozzarella")
// Returns true
redWine(layers: "sauce", "noodles", "béchamel", "meat", "mozzarella", "noodles", "ricotta", "eggplant", "béchamel", "noodles", "sauce", "mozzarella")
// Returns false
سجّل في Exercism لتتعلّم وتتقن Swift عبر 35 مفهومًا116 تمرينًا، وإرشاد بشري حقيقي، وكل ذلك مجانًا.