مسیرها
/
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 تمرین و مربی‌گری انسانی واقعی یاد بگیرید و در آن استاد شوید، همه‌ی این‌ها رایگان.