1. Навіщо потрібна конвертація типів?
Kotlin — це строго (статично) типізована мова. Якщо у компʼютера є «коробочка» для числа, то спроба покласти туди текст — приблизно те саме, що й спроба вставити виделку в USB-розʼєм. Компілятор такого не дозволить.
Утім у реальному житті ми часто працюємо з різними типами даних одночасно. Наприклад, у вас є рядок, що містить число. Саме тут і потрібна конвертація (або перетворення) типів.
Розгляньмо приклад. Припустімо, ви хочете зберігати кількість користувачів:
val a: Int = 1
val b: Int = "2"
val c: Int = "три"
Компілятор тут одразу скаже: «Я не вмію автоматично перетворювати рядок на число. Потрібно явно перетворити рядок на число».
У Kotlin є кілька способів конвертації. Кожен має свої плюси й мінуси, а також типові підводні камені.
2. Перетворюємо Int на String
У роботі часто потрібно отримати рядкове подання числа: наприклад, щоб вивести його на екран, зберегти у файл, передати мережею, обʼєднати з текстом тощо. У Kotlin для цього є відразу кілька способів — зручних у різних ситуаціях.
Функція toString()
Це основний і найпоширеніший спосіб:
val number = 42
val str = number.toString() // str == "42"
toString() перетворює значення на рядок, що відповідає типу цього значення.
Конкатенація з порожнім рядком
Старий, але робочий спосіб:
val number = 42
val str = "" + number
Такий підхід зручний у простих випадках, але для людини, яка читає код, він менш очевидний.
3. Неявне перетворення на рядок
Як уже згадували вище, у Kotlin можна перетворити на String будь-що: змінні, обʼєкти та вирази.
Ба більше, це відбувається автоматично, коли ми додаємо значення типу String до значення будь-якого іншого типу. Наприклад:
val a = 5
val name = "Аня" + a // name містить рядок Аня5
val a = 5
val city = a + "New York" + a // city містить рядок 5New York5
val number = 10
val code = "Yo"
val message = "Привіт! " + number + code // message містить рядок Привіт! 10Yo
У всіх трьох прикладах ми додавали змінні типів Int і String, а в результаті завжди отримували String.
Приклади:
val a = 5
val name = "1" + a // name містить рядок 15
val a = 5
val city = a + "9" + a // city містить рядок 595
val number = 10
val code = "10"
val message = "" + number + code // message містить рядок 1010
Операція додавання виконується зліва направо, тож результат може бути дещо несподіваним. Наприклад:
val a = 5
val name = a + a + "1" + a // name містить рядок 1015
Порядок виконання: ((a + a) + "1") + a
4. Перетворення рядка на число: toInt()
Щоб перетворити число на рядок у Kotlin, достатньо додати його до порожнього рядка:
val str = "" + число
А що робити, якщо потрібно перетворити рядок на число? Перетворити на число можна не будь-який рядок. Але якщо рядок складається лише з цифр, це можливо. Для цього в Kotlin є спеціальна функція.
Виклик виглядає так:
val x: Int = рядок.toInt()
Де val x: Int — це оголошення цілочисельної змінної x, а рядок — це число, задане у вигляді рядка (тобто рядок, що складається з цифр).
Приклади:
val str = "123"
val number1 = str.toInt() // number1 містить число 123
val number2 = "321".toInt() // number2 містить число 321
val number3 = ("321" + 0).toInt() // number3 містить число 3210
val number4: Int = "321" // Не скомпілюється: змінна типу Int, а значення типу String
Для відʼємних значень це теж працює: функція toInt() коректно обробляє знак -.
5. toIntOrNull(): безпечне перетворення на число
Коли рядок приходить із зовнішнього світу (з файлу або від користувача), завжди є ризик, що це не число. Саме тут і стане в пригоді безпечніший метод: toIntOrNull().
Він працює так: якщо рядок справді містить ціле число — поверне Int. Якщо ні — поверне null. Це принципово інша поведінка порівняно з toInt(): замість помилки під час запуску й падіння програми ми отримаємо спеціальне значення — null.
null — це спеціальне значення, яке означає «значення немає». Тобто null — це не 0, не порожній рядок і не «помилка у вигляді тексту». Це саме «відсутність результату».
Розширюємо тип Int: Int?
Тип Int зберігає лише коректні цілі числа. Він не може зберігати рядки, дробові числа, а також значення null. Тому в Kotlin є розширений варіант типу Int — Int?. Він може зберігати всі значення типу Int і значення null (коли значення немає).
Це настільки поширена ситуація, що в Kotlin її зробили частиною мови: до будь-якого типу можна додати знак питання й отримати «розширений тип», який може зберігати ще й null.
Якщо звичайний Int завжди містить число, то Int? читається як «або Int, або null». Знак питання — це буквально позначка «може бути відсутнім».
Метод toIntOrNull() повертає Int?, тому що він може як успішно розібрати число, так і не впоратися з перетворенням.
Мініприклад: успішний і неуспішний розбір
Корисно побачити, що станеться в обох випадках, і не намагатися «вгадувати» результат.
fun main() {
val ok: Int? = "15".toIntOrNull()
val bad: Int? = "15a".toIntOrNull()
println(ok) // 15
println(bad) // null
}
6. Шпаргалка та практика перетворень
Коли способів стає кілька, мозок просить «шпаргалку». І це нормально: ви не зобовʼязані тримати все в голові. Важливіше вміти швидко відновлювати сенс і добирати правильний інструмент.
Таблиця-памʼятка: toString() vs toInt() vs toIntOrNull()
| Метод | Звідки → куди | Коли використовувати | Що буде, якщо рядок не число |
|---|---|---|---|
|
|
потрібно вивести / обʼєднати з текстом | не застосовно (ми перетворюємо число) |
|
|
ви впевнені, що рядок коректний | помилка під час запуску (виняток) |
|
|
рядок може бути «неохайним» | поверне null |
Чому Kotlin змушує робити перетворення явними
Коли люди вперше стикаються з явними перетвореннями, часто виникає запитання: «Чому мова сама не здогадається, що "123" — це число?» Але мова якраз не хоче вгадувати.
Уявіть: ви написали "007". Це число сім? Чи це код відділу? Або ж рядок, у якому важливі провідні нулі? Якби мова автоматично перетворювала рядки на числа, вона регулярно помилялася б. Kotlin обирає передбачуваність: якщо вам потрібне число — викличте toInt() або toIntOrNull() і свідомо ухваліть це рішення.
Це, по суті, «доросла» позиція мови. Kotlin ніби каже: «Я не телепат. Я компілятор».
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ