المسارات
/
Swift
Swift
/
التمارين
/
العميل السري Double-Null0111
العميل السري Double-Null0111

العميل السري Double-Null0111

تمرين تعلّمي

مقدمة

أنواع الدوال

إذا أزلنا كل الأسماء والتسميات من توقيع دالة Swift، فسيتبقى لنا نوع الدالة.

func shoppingList(item: String, quantity: Int) -> String {
  "You need to buy \(quantity) \(item)."
}
// shoppingList: (String, Int) -> String

func repeater(_ phrase: String, times: Int) -> String {
  var result = ""
  for _ in 1...times {
    result += phrase
  }
  return result
}
// repeater: (String, Int) -> String

func printString(line: String) {
  print(line)
}
// printString: (String) -> ()

لاحِظ أن نوعي الدالتين الأولى والثانية متماثلان، (String, Int) -> String، رغم أن التوقيعين مختلفان وأن الدالتين تعملان بطريقتين مختلفتين تمامًا. فكلتاهما تأخذان String وInt كمدخل وتُرجعان String. وكما يتبين من نوع الدالة الثالثة، فرغم أن جسم الدالة لا يبدو أنه يُرجع أي شيء، فإنه في الواقع يُرجع () ضمنيًا، وهي القيمة الوحيدة من النوع Void.

يمكن استخدام أنواع الدوال هذه بالطريقة نفسها التي تُستخدم بها أي أنواع أخرى في Swift، فمثلًا يمكن استخدامها في تعريف المتغيرات أو الثوابت. وبما أن الدوال قيم في Swift، يمكن إسناد الدوال الموجودة بالفعل إلى هذه الثوابت/المتغيرات:

var stringAndIntToString: (String, Int) -> String

stringAndIntToString = shoppingList
stringAndIntToString("carrots", 3)
// => "You need to buy 3 carrots."

وكما هو الحال مع المتغيرات/الثوابت الأخرى، يجب أن تكون القيمة التي تُسندها من النوع الصحيح:

stringAndIntToString = printShoppingList
// Error: Cannot assign value of type '(String) -> ()' to type '(String, Int) -> String'

أنواع الدوال كأنواع للمعاملات

وبما أنه يمكن استخدام أنواع الدوال في أي مكان يمكن استخدام أنواع أخرى فيه، فإنه يترتب على ذلك أنه يمكن استخدامها كأنواع للمعاملات، وتمريرها إلى دوال أخرى، واستدعاؤها من داخل تلك الدوال.

func apply3(to str: String, function f: (String, Int) -> String) -> String {
  f(str,3)
}
// apply3: ([String], (String, Int) -> String) -> [String]

apply3(to: "eggs", function: shoppingList)
// => "You need to buy 3 eggs."

apply3(to: "eggs", function: repeater)
// => "eggseggseggs"

أنواع الدوال كأنواع للإرجاع

وبالمثل، يمكن استخدام أنواع الدوال كأنواع للإرجاع في الدوال. بعبارة أخرى، يمكن كتابة دوال تُنشئ وتُرجع دوال أخرى. وعند إنشاء هذه الدوال، يمكن للدالة التي تُرجَع أن تستخدم المعاملات الأخرى الممرَّرة إلى الدالة أو المتغيرات المحلية المُنشأة داخل الدالة الأم.

func makeAdder(base: Int) -> (Int) -> Int {
  func adder(_ i: Int) -> Int {
    base + i
  }
  return adder
}
// makeAdder: (Int) -> (Int) -> Int

let add10 = makeAdder(base: 10)
// add10: (Int) -> Int

let subtract20 = makeAdder(base: -20)
// subtract10: (Int) -> Int

add10(5)
// => 15

subtract20(5)
// => -15

التعليمات

مرحبًا، أيها العميل Double-Null0111.

مهمتك، إن اخترت قبولها، هي كتابة أداتين تساعدانك على التسلل إلى مقر UMBRA (United Minions Being Really Awful) واستعادة مخططات أحدث خططهم الشنيعة. ستحتاج إلى أداتين لإنجاز هذه المهمة.

1. احمِ الخطط السرية المستعادة بكلمة مرور

بعد حصولك على الخطط السرية، ستحتاج إلى حمايتها بحيث لا يتمكن من استعادتها إلا من يعرف كلمة المرور.

للقيام بذلك، ستحتاج إلى تنفيذ الدالة protectSecret(_ secret: String, withPassword password: String) -> (String) -> String. ستُرجع هذه الدالة دالة أخرى تأخذ سلاسل نصية محتملة لكلمات المرور كمدخل. إذا كانت كلمة المرور المُدخَلة صحيحة، تُرجع الدالة الجديدة السر المخفي، أما إذا كانت كلمة المرور غير صحيحة، فتُرجع الدالة "Sorry. No hidden secrets here."

let secretFunction = protectSecret("Steal the world's supply of french fries!", withPassword: "5up3r53cr37")

secretFunction("Open sesame")
// Returns "Sorry. No hidden secrets here."

secretFunction("5up3r53cr37")
// Returns "Steal the world's supply of french fries!"

2. أنشئ تركيبة لفتح خزنتهم

علمنا أن UMBRA تبني جميع تركيبات خزائنها على رقم الغرفة التي تقع فيها. تُولَّد تركيبات الخزنة بتطبيق دالة خاصة على رقم الغرفة بشكل متكرر. لذا فإن الرقم الأول في التركيبة ينتج عن تطبيق الدالة على رقم الغرفة، والثاني ينتج عن تطبيق الدالة على الرقم الأول، والثالث عن تطبيق الدالة على الرقم الثاني.

ومع ذلك، تغيّر UMBRA بانتظام الدالة المستخدمة لتوليد التركيبات، لذا ستحتاج أداتك إلى أخذ رقم الغرفة والدالة المناسبة معًا لتوليد التركيبة.

نفّذ الدالة generateCombination(forRoom room: Int, usingFunction f: (Int) -> Int) -> (Int, Int, Int) لتوليد التركيبة التي ستحتاج إليها.

func makeCombo(_ x: Int) -> Int {
  (x * 13) % 256
}

generateCombination(forRoom: 227, usingFunction: makeCombo)
// Returns (135, 219, 31)
تعديل عبر GitHub يفتح الرابط في نافذة أو علامة تبويب جديدة
Swift Exercism

مستعد لبدء العميل السري Double-Null0111؟

سجّل في Exercism لتتعلّم وتتقن Swift عبر 35 مفهومًا116 تمرينًا، وإرشاد بشري حقيقي، وكل ذلك مجانًا.