JavaRush /Курси /Swift SELF /Мітки аргументів: імена параметрів і читабельність виклик...

Мітки аргументів: імена параметрів і читабельність викликів

Swift SELF
Рівень 9 , Лекція 2
Відкрита

1. Навіщо потрібні argument labels

Коли ви вперше бачите виклик Swift на кшталт distance(from: 3, to: 10), може здатися, що для двох чисел це забагато літер. Але ці «літери» — не прикраса. Вони одночасно допомагають і компілятору, і людині: компілятору — перевіряти коректність виклику, а людині — читати код як фразу, не тримаючи в памʼяті порядок параметрів. А памʼять, як відомо, і так зайнята паролями від Wi‑Fi.

Swift від самого початку проєктували з ідеєю, що добрий код читається майже як природна мова. Тому argument labels стають частиною «публічного обличчя» функції: вони показують зміст кожного аргумента і зменшують шанс переплутати два значення однакового типу, наприклад два Int або два String.

Приклад: без labels і з labels

Порівняйте два варіанти: обидва компілюються, але один читається як «набір чисел», а інший — як «зрозуміла операція»:

func rectangleArea(_ a: Int, _ b: Int) -> Int {
    return a * b
}

print(rectangleArea(3, 7)) // 21
func rectangleArea(width: Int, height: Int) -> Int {
    return width * height
}

print(rectangleArea(width: 3, height: 7)) // 21

У другому випадку ви майже фізично не можете випадково переплутати аргументи місцями, тому що компілятор змусить вас підписати кожне значення: width: і height:.

2. Зовнішні та внутрішні імена параметрів

Тепер розберімо важливу основу. У Swift у параметра функції часто є зовнішнє імʼя (argument label) — те, що пишеться під час виклику, і внутрішнє імʼя — те, чим ви користуєтеся всередині тіла функції. Іноді вони збігаються, іноді — різні. Сенс у тому, щоб одночасно досягти читабельного виклику і зручного коду всередині функції.

Давайте розкладемо це в маленьку таблицю, щоб мозок не намагався зберігати правило у вигляді «відчуваю, що так треба»:

Що це Де використовується Як виглядає
Зовнішнє імʼя (label) у місці виклику
distance(from: 3, to: 10)
Внутрішнє імʼя усередині
func { ... }
return end - start

Коли зовнішнє та внутрішнє імена збігаються

Ось приклад функції, де зовнішнє та внутрішнє імена збігаються:

func greet(name: String) -> String {
    return "Привіт, \(name)!"
}

print(greet(name: "Анно")) // Привіт, Анно!

Коли імена різні

А ось приклад, де в оголошенні ми явно задаємо зовнішній і внутрішній варіанти:

func greet(to name: String) -> String {
    return "Привіт, \(name)!"
}

print(greet(to: "Анно")) // Привіт, Анно!

Зверніть увагу: всередині функції змінна називається name, а зовні ми викликаємо її як to:. Виклик читається як «greet to Анно», тобто «привітай Анно». Це майже як англійська, але без обовʼязкової граматики і з меншою кількістю неправильних дієслів.

Такий стиль безпосередньо підтримує ідею «читаємо як речення» та відповідає Swift API Design Guidelines: мітки аргументів мають допомагати читанню і не змушувати користувача домислювати зміст параметрів.

3. Коли варто прибирати label через _

Іноді мітка справді зайва. Якщо параметр — головний «обʼєкт дії», а зміст очевидний, Swift дозволяє прибрати зовнішню мітку за допомогою _. Це робить виклик коротшим, але не має робити його загадковішим.

Класичний приклад — функція «квадрат числа». Якщо ми написали square(x: 6), це не помилка, але трохи багатослівно. Зазвичай пишуть так:

func square(_ x: Int) -> Int {
    return x * x
}

print(square(6)) // 36

Але ось де _ уже шкодить — це коли параметрів кілька, особливо якщо вони одного типу. Тоді f(10, 20) перестає бути кодом і перетворюється на два числа, які ви ніби відправили в космос без підписів.

Порівняйте:

func distance(_ start: Int, _ end: Int) -> Int {
    return end - start
}

print(distance(3, 10)) // 7

і більш читабельний варіант:

func distance(from start: Int, to end: Int) -> Int {
    return end - start
}

print(distance(from: 3, to: 10)) // 7

У другому випадку ви бачите не просто два числа, а й звʼязок між ними: from і to. І це якраз той випадок, коли «зайві букви» економлять час на розуміння.

Практичне правило на сьогодні просте: прибирайте мітку через _ лише тоді, коли без неї виклик залишається абсолютно очевидним. Якщо вам доводиться памʼятати порядок аргументів, отже, мітка має бути.

4. Як обирати імена зовні та всередині

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

Подивімося на приклад перевірки, чи лежить число в діапазоні. Зовні ми хочемо побачити щось на кшталт «значення в діапазоні від ... до ...». Усередині ж нам зручніше оперувати minValue і maxValue.

func isInRange(_ value: Int, from minValue: Int, to maxValue: Int) -> Bool {
    return value >= minValue && value <= maxValue
}

print(isInRange(7, from: 1, to: 10)) // true

Тут усе зроблено з урахуванням читабельності.

Виклик починається з головного аргумента — isInRange(7, from:), тому перший параметр без мітки. А ось межі діапазону обовʼязково підписані, інакше isInRange(7, 1, 10) виглядає як «7, 1, 10 — здогадайся, що де».

Ще один корисний прийом — використовувати зовнішні слова, які роблять виклик схожим на фразу. При цьому всередині можна залишити коротке імʼя, щоб код не виглядав як твір на 10 сторінок:

func makeGreeting(for personName: String) -> String {
    return "Вітаю, \(personName)!"
}

print(makeGreeting(for: "Мишо")) // Вітаю, Мишо!

Зовні ми бачимо for:, тобто «привітання для когось», а всередині використовуємо personName — зрозуміле робоче імʼя.

Мітки — ключові слова

Якщо ви дивилися на виклики стандартної бібліотеки, ви могли помітити мітки на кшталт in, for, to, by. Виникає питання: «Зачекайте, але in — це ж ключове слово в циклах. Як це взагалі дозволено?»

У Swift це дозволено: більшість ключових слів можна використовувати як argument labels, інакше багато природних API довелося б називати дивними словами-замінниками. Це закріплено на рівні дизайну мови: ідея саме в тому, щоб виклики читалися природно.

Давайте зробимо мініприклад, який компілюється і виглядає як «англійська фраза», навіть якщо ви не фанат англійської:

func isAffordable(_ price: Double, in budget: Double) -> Bool {
    return price <= budget
}

print(isAffordable(99.9, in: 120.0)) // true

Тут in: — вдала мітка. Вона додає сенс: «чи доступно це за ціною в межах бюджету». І найприємніше: під час виклику видно, що друге число — саме бюджет, а не «ще одне число такого ж типу, яке я випадково передав».

Поєднання «вдалі мітки + вдалі імена функцій» — це практично міні-документація прямо в коді. І це не філософія, а банальна економія часу на читання.

5. Приклад: консольний застосунок BudgetBuddy

Зараз зберемо невеликий приклад, який стане нашим поточним навчальним проєктом. Нехай це буде простий консольний застосунок BudgetBuddy: він запитує бюджет, ціну товару та податок, рахує підсумкову вартість і показує, чи вкладаємося ми в бюджет. Жодних масивів, класів і решти майбутніх радощів — тільки те, що ви вже проходили.

Почнемо з маленької функції введення. Тут мітка особливо корисна: ми хочемо читати виклик як «прочитай число з підказкою».

func readDouble(prompt: String) -> Double {
    print(prompt, terminator: ": ")
    return Double(readLine() ?? "") ?? 0
}

let budget = readDouble(prompt: "Введіть бюджет")
print(budget) // наприклад: 100.0

Зверніть увагу: prompt: — вдала мітка, бо вона відповідає на запитання «що це за рядок?».

Тепер винесімо розрахунок підсумкової ціни. Тут нам хочеться, щоб виклик був максимально прозорим. Варіант без міток швидко стає нечитабельним, тому залишімо їх:

func totalPrice(for price: Double, taxPercent percent: Double) -> Double {
    return price + price * percent / 100
}

let total = totalPrice(for: 80, taxPercent: 20)
print(total) // 96.0

Тут ми зробили дві важливі речі. По-перше, зовнішня мітка for: допомагає читати «підсумкова ціна для ціни X». По-друге, для другого параметра ми використовуємо зовнішнє taxPercent, а внутрішнє — коротке percent, щоб усередині формули не було довгої назви. Формула й так не мріє про гуманітарний факультет.

Залишилося порівняти з бюджетом. І тут чудово працює мітка in::

func isAffordable(_ price: Double, in budget: Double) -> Bool {
    return price <= budget
}

print(isAffordable(96, in: 100)) // true

Зберімо все в невеликий фрагмент коду верхнього рівня. Це все ще top-level code, як у Web-IDE, і він компілюється:

func readDouble(prompt: String) -> Double {
    print(prompt, terminator: ": ")
    return Double(readLine() ?? "") ?? 0
}

func totalPrice(for price: Double, taxPercent percent: Double) -> Double {
    return price + price * percent / 100
}

func isAffordable(_ price: Double, in budget: Double) -> Bool {
    return price <= budget
}

let budget = readDouble(prompt: "Бюджет")
let price = readDouble(prompt: "Ціна товару")
let tax = readDouble(prompt: "Податок, %")

let total = totalPrice(for: price, taxPercent: tax)

print("Підсумкова ціна: \(total)")
// Наприклад: Підсумкова ціна: 96.0

if isAffordable(total, in: budget) {
    print("Покупка вкладається в бюджет.") // наприклад: Покупка вкладається в бюджет.
} else {
    print("Не вкладається в бюджет.")      // наприклад: Не вкладається в бюджет.
}

Зауважте цікаву річ: якщо ви відкриєте цей код за місяць, ви зрозумієте його майже без коментарів — саме тому, що виклики функцій самі пояснюють зміст аргументів.

6. Помилки labels і підказки IDE

Оскільки мітки є частиною контракту виклику, компілятор дуже суворо стежить за ними. Це іноді дратує новачків: «Ну ти ж зрозумів, що я хотів передати другим аргументом. Чого ти чіпляєшся?» Але такі причіпки тут як ремінь безпеки: вони заважають лише до першого реального зіткнення.

Наприклад, якщо функція очікує bar: як мітку, а ви викликаєте без неї, Swift дасть помилку на кшталт missing argument label ... in call. Такі діагностики — нормальна частина досвіду розробки: компілятор підказує, яку саме мітку ви забули.

Уявімо, що ви забули мітку prompt::

func readDouble(prompt: String) -> Double {
    print(prompt, terminator: ": ")
    return Double(readLine() ?? "") ?? 0
}

readDouble("Бюджет") // ❌ Помилка: missing argument label 'prompt:' in call

Це не примха Swift, а захист від ситуації, коли у вас 3–4 параметри одного типу і ви випадково викликаєте функцію не так, як думали.

І ось ще важлива думка: мітки допомагають не лише компілятору, а й автодоповненню в IDE. Коли ви пишете totalPrice(, IDE одразу підказує for: і taxPercent: — і ви вже менше помиляєтеся суто механічно.

7. Типові помилки під час роботи з мітками аргументів

Помилка № 1: прибирати мітки «для краси», а потім плутатися в аргументах.
Дуже часта історія: людина бачить, що можна писати f(10, 20), і робить так усюди, бо коротше. Через день зʼясовується, що вона вже не памʼятає, де ширина, де висота, де початок, а де кінець. Якщо параметри однакового типу і зміст не очевидний, мітки — це не розкіш, а спосіб не перетворювати код на загадку.

Помилка № 2: плутати зовнішнє і внутрішнє імʼя параметра.
Якщо ви оголосили func greet(to name: String), то під час виклику потрібно писати greet(to: "Анно"), а не greet(name: "Анно"). Внутрішнє імʼя name існує для тіла функції, а зовнішня мітка to: — для читабельного виклику. Коли мозок це плутає, здається, що компілятор чіпляється до слів, але насправді він захищає контракт API.

Помилка № 3: робити виклик виду f(1, 2, 3) і сподіватися, що читач здогадається.
Такий стиль може зійти в математичній бібліотеці, де в усіх однозначні правила, але в прикладному коді це майже завжди погіршує розуміння. Якщо без мітки не можна зрозуміти зміст аргумента без перегляду оголошення функції, отже, мітка потрібна.

Помилка № 4: робити надто довгі мітки, які не додають сенсу.
Іноді новачки намагаються «максимально описати все» і отримують щось на кшталт totalPrice(forPrice:taxPercentValue:). Це вже перебір. Мітка має додавати сенс, а не дублювати імʼя функції. Хороший сигнал якості: виклик читається як фраза і не виглядає як тавтологія.

Помилка № 5: ігнорувати стиль «читаємо як речення» і ставити випадкові слова.
Мітки на кшталт a:, b:, x1:, x2: не допомагають читанню і зазвичай означають, що функцію спроєктовано не надто вдало або ви просто поспішали. Навіть у навчальних завданнях краще привчати себе до промовистих міток: from/to, in, for, min/max — тому що потім ця звичка переноситься на реальний код майже без зусиль.

Коментарі
ЩОБ ПОДИВИТИСЯ ВСІ КОМЕНТАРІ АБО ЗАЛИШИТИ КОМЕНТАР,
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ