Треки
/
Swift
Swift
/
Вправи
/
Майстер лазаньї
Майстер лазаньї

Майстер лазаньї

Навчальна вправа

Вступ

Типові значення параметрів

Типові значення параметрів можна задати для будь-якого параметра функції, присвоївши значення параметру в списку параметрів після анотації типу цього параметра. Коли типове значення параметра вказано, той, хто викликає функцію, може пропустити цей параметр під час виклику, і замість нього буде використано типове значення.

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
Note

Якщо функція має додаткові параметри після варіативного, то перший параметр після варіативного обовʼязково повинен мати явну мітку аргументу, щоб Swift знав, де закінчується список варіативних аргументів.

In-out параметри

У тілі функції параметри вважаються константами, а не змінними; спроба змінити значення параметра призведе до помилки часу компіляції. Якщо функція хоче змінити значення параметра, вона має використати in-out параметр, щоб явно позначити цю змінність.

Щоб скористатися in-out параметрами, програміст має подбати про три речі:

  1. У визначенні функції треба явно позначити in-out параметри, написавши ключове слово inout між : і назвою типу в анотації типу параметра.
  2. Значення, яке передають в in-out параметр, має бути оголошене як змінна, а не як константа. Так само воно не може бути літералом.
  3. Перед назвою змінної у виклику функції треба поставити &, явно позначаючи її як таку, що можна змінювати.

Коли все це зроблено, функція створить внутрішню копію in-out параметра, змінить її відповідно до тіла функції, а потім скопіює змінене значення назад у змінну, яку передали, коли функція поверне результат.

func updateVersion(_ record: inout (version: Int, title: String)) {
  record.version += 1
}

var dbRecord = (version: 2, title: "Exercism")
updateVersion(&dbRecord)

// dbRecord is now (3, "Exercism")
Щодо in-out параметрів варто памʼяти про ще кілька додаткових правил.

1  Усередині функції з in-out параметрами не можна посилатися на змінну, яку передали як in-out параметр.
2.  Ту саму змінну не можна передати як кілька in-out параметрів в одній функції.
    Наприклад, `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

Вкладені функції поводяться як звичайні функції, але їхня видимість обмежена тілом функції, що їх містить.

Вказівки

У цій вправі ми напишемо ще трохи коду, який допоможе приготувати чудову лазанью з нашої улюбленої кулінарної книги.

На нас чекають пʼять завдань, і всі вони повʼязані з часом, витраченим на приготування лазаньї.

1. Дозвольте змінювати очікуваний час у печі

Ми хочемо написати покращену функцію remainingMinutesInOven, яка приймає як параметр кількість хвилин, що лазанья вже провела в печі, і повертає, скільки хвилин їй ще залишилося там побути, виходячи з очікуваного часу в печі в хвилинах із попереднього завдання. Раніше ми покладалися на константу expectedMinutesInOven, яка була визначена поза функцією remainingMinutesInOven. Це було і трохи заплутано на наш смак, і недостатньо гнучко, бо не давало змоги змінити очікуваний час у печі.

Щоб навести лад, визначте функцію remainingMinutesInOven, яка приймає як параметр кількість хвилин, що лазанья вже провела в печі, а також параметр expectedMinutesInOven із типовим значенням 40. Наша функція повинна повертати, скільки хвилин лазаньї ще залишилося побути в печі, виходячи з очікуваного часу в печі в хвилинах із попереднього завдання.

remainingMinutesInOven(elapsedMinutes: 30)
// Returns 10
remainingMinutesInOven(elapsedMinutes: 30, expectedMinutesInOven: 75)
// Returns 45

2. Дозвольте різну кількість шарів

Раніше ми написали функцію preparationTimeInMinutes, яка приймає як параметр кількість шарів, доданих до лазаньї, і повертає, скільки хвилин ми витратили на підготовку лазаньї, якщо припустити, що на кожен шар іде 2 хвилини. Однак ця функція нас не дуже тішить, бо перед її викликом доводиться самому рахувати шари в лазаньї, а кому хочеться витрачати на це час?

Щоб спростити собі життя, напишіть функцію 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

3. Обчисліть кількість локшини та соусу

Перш ніж складати лазанью, ми хочемо переконатися, що соусу й локшини вистачить на лазанью нашої мрії. На кожен шар локшини в лазаньї потрібно 3 аркуші локшини. На кожен шар соусу в лазаньї потрібно 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)

4. Перетворіть літри на рідкі унції на місці

На жаль, обʼєм соусу, який у нас є, вказано в рідких унціях, а не в літрах. Щоб знати, чи вистачить соусу, напишіть функцію toOz, яка приймає in-out параметр-кортеж (noodles: Int, sauce: Double) і перетворює кількість соусу на рідкі унції. Зауважте, що в одному літрі 33,814 рідкої унції.

var amount = (noodles: 9, sauce: 0.8)
toOz(&amount)

amount
// Returns (noodles: 9, sauce: 27.0512)

5. Визначте найкраще вино до столу

Насамкінець, ми хочемо знати, яке вино подати до лазаньї. Ми чули, що біле вино варто подавати, якщо в лазаньї більше моцарели, рикоти й бешамелю, ніж мʼяса та соусу, а інакше - червоне. Напишіть функцію redWine, яка приймає варіативний параметр String layers, де ми перелічуємо різні шари лазаньї. Функція за допомогою пʼяти вкладених функцій визначить кількість шарів моцарели, рикоти, бешамелю, соусу та мʼяса в лазаньї й порівняє їх, щоб вирішити, чи слід подавати червоне вино, повертаючи 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
Редагувати через GitHub Посилання відкривається в новому вікні або вкладці
Swift Exercism

Час розпочати Майстер лазаньї?

Зареєструйтеся на Exercism, щоб вивчати й опановувати Swift, а також 35 концепцій116 вправ та справжнє наставництво від людей, і все це безкоштовно.