JavaRush /Курси /Swift SELF /Перетворення введених даних: Int(line), Double(line)

Перетворення введених даних: Int(line), Double(line)

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

1. Мені потрібне число

Коли ви розвʼязуєте консольні задачі, введені дані майже завжди мають вигляд тексту: навіть якщо користувач вводить 42, програма спочатку отримує рядок "42". І тут виникає класична ситуація: за змістом це число, бо ми хочемо додавати, ділити й порівнювати, а фактично — текст. Якщо не виконати перетворення, програма не рахуватиме, а поводитиметься з рядками: склеюватиме їх, друкуватиме й підсумовуватиме.

Уявіть, що ви замовили в кафе дві кави, а вам принесли папірець із написом 2. Технічно це «два», але випити це неможливо. Перетворення рядка на число — це наш спосіб перетворити напис на реальну кількість кави.

Рядок — це ще не число

let text = "10"
print(text + text) // 1010

Пояснення: це не «двадцять», а просто склеювання "10" і "10". Щоб отримати 20, треба перетворити значення на число.

2. Знайомство з Int() і Double()

Swift — сувора мова: вона не виконує неявних перетворень, щоб випадково не накоїти лиха. Якщо у вас є рядок, а ви хочете отримати з нього число, вам потрібно написати Int(string). Або Double(string), якщо рядок містить дробове число. Приклад:

let five = "5"
let two = "2.0"

let a = Int(five)        				// Int?
let b = Double(two)     				// Double?

// let sum = a + b               // ❌ помилка: різні типи
let sum = Double(a) + b          // ✅ спочатку перетворюємо Int на Double
print(sum)                        // 7.0

Спочатку ми перетворили рядки five і two на числа: ціле й дробове. Потім додали їх. Довелося попередньо перетворити ціле на дробове, тому що Swift не любить додавати числа з різними типами.

Чому це важливо саме для введення

Користувач вводить текст, але за змістом ви заздалегідь знаєте, що очікуєте:

  • «вік» → Int
  • «ціна» → Double

Отже, далі ви перетворюватимете рядок на потрібний тип. Але тут є пастка: рядок може виявитися неправильним. Тому Swift не гарантує успіху — і повертає Optional. Саме до цього ми й переходимо.

3. Int(...) і Double(...) повертають Optional

Тепер головне відкриття лекції: у Swift перетворення рядка на число може не вдатися, тому результат — опційний.

Тобто:

  • Int("123") повертає Int?
  • Double("3.14") повертає Double?

Чому так? Тому що рядок може бути нечисловим: "abc", "12a", "3,14" (якщо очікується крапка), порожній рядок "". Swift не хоче вдавати, що все добре. Він чесно каже: «Я спробував. Якщо вийшло — тримай число. Якщо ні — тримай nil».

Успішне перетворення

let value = Int("42")
print(value) // Optional(42)

Так, print() покаже Optional(42) — це нормально: «у мене не просто число, а коробочка, в якій може бути число».

Невдале перетворення

let value = Int("cat")
print(value) // nil

4. Де в ланцюжку «ввід → число» зʼявляється nil

Тут легко заплутатися, тому розкладемо по поличках. У нашому ланцюжку є дві окремі точки, де все може стати nil.

Перша — readLine() може повернути nil, якщо введення відсутнє. Друга — навіть якщо рядок є, Int(line) може повернути nil, якщо рядок не схожий на число.

Корисно тримати в голові просту схему:

flowchart TD
    A["readLine()"] --> B{Рядок є?}
    B -- ні --> N1[nil]
    B -- так --> C["Int(line) / Double(line)"]
    C --> D{Це число?}
    D -- ні --> N2[nil]
    D -- так --> OK[Число]

Саме тому в задачах часто радять спочатку підстрахуватися від nil, а потім ще раз перевірити результат.

5. Оператор ??: «якщо nil — візьми запасний варіант»

Тепер наш найкращий друг на найближчі задачі — оператор ?? (nil-coalescing operator). Він означає:

«Якщо зліва nil, візьми те, що справа. Якщо зліва не nil, візьми ліве».

Важливий момент: ?? застосовується, коли зліва Optional. У сучасному Swift це суворо: якщо зліва не Optional, використовувати ?? не можна — і це добре, бо інакше можна випадково приховати помилку.

Приклад: підставляємо значення за замовчуванням для String?

let line: String? = nil
let safeLine = line ?? "0"
print(safeLine) // 0

safeLine — уже звичайний рядок String, не опціональний.

Приклад: підставляємо значення за замовчуванням для Int?

let parsed: Int? = Int("not a number")
let value = parsed ?? 0
print(value) // 0

6. Патерн: введення → розбір → значення за замовчуванням

Зберемо все в один практичний рецепт. Він трохи довший, зате передбачуваний і добре підходить новачкам. Та й менторам теж — особливо коли код не падає на перевірці.

Варіант А: компактно (в один рядок)

let number = Int(readLine() ?? "") ?? 0
print(number)

Тут відбуваються одразу дві підстраховки:

Спочатку readLine() ?? "" гарантує рядок, навіть порожній, а потім Int(...) ?? 0 гарантує число.

Код робочий, але в ньому легко заплутатися через велику кількість дужок.

Варіант B: читабельно (кілька кроків)

let line = readLine()           // String?
let safeLine = line ?? ""       // String
let number = Int(safeLine) ?? 0 // Int
print(number)

Цей стиль часто кращий для навчання: ви бачите, де саме був Optional і де саме від нього позбулися.

7. Корисні нюанси

Int vs Double: ціла кількість і дробова частина

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

  • Int — для «штук»: кількість книг, вік, число студентів, коробки, лайки.
  • Double — коли можлива дробова частина: ціна 19.99, вага 2.5, середнє значення 3.75.

І так, гроші — тонка тема, але в межах цього рівня ми використовуємо Double просто як «число з крапкою».

Уявляйте це як вибір контейнера: якщо ви рахуєте яблука, беріть коробку для цілих яблук (Int). Якщо ви рахуєте сік у літрах, беріть мірний стакан (Double).

Приклад: парсимо Double зі значенням за замовчуванням

let price = Double(readLine() ?? "") ?? 0.0
print(price)

Чому значення за замовчуванням 0.0, а не 0? Тому що тип має збігатися: праворуч від ?? має бути значення того самого типу, який ви хочете отримати.

Памʼятка: які типи повертаються

Іноді мозок намагається запамʼятати це як заклинання, але краще подивитися на таблицю.

Вираз Тип результату Чому
readLine()
String?
введення може бути відсутнім
readLine() ?? ""
String
?? підставив значення за замовчуванням
Int("123")
Int?
рядок може не містити числа
Int(text) ?? 0
Int
?? підставив число за замовчуванням
Double("3.14")
Double?
рядок може не містити числа
Double(text) ?? 0.0
Double
значення за замовчуванням для Double

8. Мініпроєкт: калькулятор чайових

Далі продовжимо ідею: ми збираємо один і той самий застосунок частинами. Сьогодні це буде дуже простий консольний помічник: користувач вводить суму рахунку та відсоток чайових, а програма рахує підсумок.

Ми поки що не вміємо красиво обробляти неправильне введення (це знадобиться пізніше), тож діємо прагматично: якщо введення неправильне, використовуємо значення за замовчуванням.

Крок 1: читаємо суму рахунку як Double

let billText = readLine() ?? ""
let bill = Double(billText) ?? 0.0
print("Рахунок: \(bill)")

Якщо введуть 120.5 — чудово. Якщо введуть «котик» — рахунок стане 0.0. Неприємно для ресторану, але приємно для компілятора.

Крок 2: читаємо відсоток чайових як Int і переводимо в частку

Відсоток зручно вводити цілим числом: 10, 15, 20.

let tipPercentText = readLine() ?? ""
let tipPercent = Int(tipPercentText) ?? 0

let tipRate = Double(tipPercent) / 100.0
print("Чайові: \(tipPercent)%")

Зверніть увагу: ми перетворюємо Int на Double через Double(tipPercent), тому що інакше ділення було б цілочисельним, а нам потрібен дріб.

Крок 3: рахуємо підсумок

let billText = readLine() ?? ""
let bill = Double(billText) ?? 0.0

let tipPercentText = readLine() ?? ""
let tipPercent = Int(tipPercentText) ?? 0
let tipRate = Double(tipPercent) / 100.0

let total = bill + bill * tipRate
print("Разом: \(total)")

Код вийшов трохи довгим, але це усвідомлена плата за зрозумілість: ви бачите кожен крок, і вам простіше налагоджувати.

9. Типові помилки

Помилка №1: «Я впевнений, що на вході число, тож пишу так, ніби Optional не існує».
Зазвичай це виглядає як спроба одразу працювати з readLine() як із рядком або з Int(readLine()) як із числом. Компілятор не дасть зробити це «нишком», і це його спосіб урятувати вас від падіння програми. Звикайте: якщо бачите ? у типі — це червоний прапорець: значення може бути відсутнім.

Помилка №2: підстрахували readLine(), але забули, що Int(...) теж може повернути nil.
Дуже частий сценарій: людина пише let line = readLine() ?? "0", а потім робить let x = Int(line) і думає, що x — це Int. Але x усе ще Int?. Тому «подвійна підстраховка» (?? після readLine() і ?? після Int(...)) — не параноя, а реальність.

Помилка №3: неправильне значення за замовчуванням за типом (0 замість 0.0 або навпаки).
Int(...) ?? 0.0 не скомпілюється, і це правильно: праворуч має бути Int. Аналогічно Double(...) ?? 0 іноді не проходить перевірку типів за строгих перевірок. Звикайте обирати значення за замовчуванням «у стилі типу»: для Int0, для Double0.0.

Помилка №4: спроба розібрати дріб через Int.
Якщо користувач вводить 3.14, а ви робите Int("3.14"), отримаєте nil і раптово перейдете до значення за замовчуванням. Якщо за змістом можлива дробова частина — використовуйте Double. Якщо за змістом має бути ціле число — використовуйте Int і не сподівайтеся, що 3.0 «якось само» стане цілим.

Помилка №5: «магічний рядок» у значенні за замовчуванням, який ламає логіку.
Іноді хочеться написати readLine() ?? "1" «бо так менше шансів на ділення на нуль». Але це робить програму дивною: відсутність введення перетворюється на конкретне значення і спотворює результат. Значення за замовчуванням треба обирати свідомо: або 0 як «нічого не ввели», або таке значення, яке за змістом безпечніше саме у вашій задачі, і ви можете це пояснити.

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