Урок 3 из 8 · 25 мин · обновлено
Основы Kotlin: переменные, функции и защита от null
Главное из Kotlin для первых экранов: val и var, типы, строковые шаблоны, if и when, функции, списки и классы данных, а также как Kotlin защищает от ошибок с null.
val и var
Kotlin, как и Java, компилируемый язык со строгими типами, но писать на нём заметно короче. Переменные объявляют двумя словами:
val name = "Молоко" // нельзя переназначить
var count = 2 // можно менять
count = 3
val— значение, которое после присваивания не меняется. По умолчанию пишут именно его;var— переменная, когда значение действительно должно меняться.
Тип Kotlin определяет сам, но его можно указать явно через двоеточие:
val price: Int = 89
val weight: Double = 1.5
val inStock: Boolean = true
Основные типы: Int — целые числа, Double — дробные, String — строки, Boolean — true или false.
Строковые шаблоны подставляют значения прямо в текст:
println("$name: $count шт., итого ${price * count} ₽")
Молоко: 3 шт., итого 267 ₽
Знак $ подставляет переменную, а для выражения добавляют фигурные скобки.
if, when и функции
В Kotlin if и when возвращают значение, поэтому их можно сразу присвоить:
val delivery = if (total >= 1500) 0 else 199
val label = when (count) {
0 -> "нет в списке"
1 -> "одна штука"
else -> "$count шт."
}
when — более мощный аналог switch: проверяет значение по вариантам сверху вниз, else срабатывает, если ничего не подошло.
Функции объявляют через fun, тип результата пишут после двоеточия:
fun total(price: Int, count: Int): Int {
return price * count
}
fun discount(price: Int, percent: Int = 10): Int = price * (100 - percent) / 100
println(total(89, 3))
println(discount(1000))
println(discount(1000, percent = 25))
267
900
750
Если функция умещается в одно выражение, вместо фигурных скобок пишут =. У параметра может быть значение по умолчанию, а при вызове параметры можно называть по имени — так понятнее, что за число передано.
Списки и классы данных
data class Product(val name: String, val count: Int)
val products = listOf(
Product("Молоко", 2),
Product("Хлеб", 1),
Product("Яблоки", 6),
)
for (p in products) {
println("${p.name} — ${p.count}")
}
val many = products.filter { it.count > 1 }
println(many.map { it.name })
Молоко — 2
Хлеб — 1
Яблоки — 6
[Молоко, Яблоки]
data class— класс для хранения данных. Kotlin сам добавит ему сравнение, копирование и понятный вывод;listOfсоздаёт неизменяемый список,mutableListOf— изменяемый, в который можно добавлять;filterиmapпринимают лямбду — кусок кода в фигурных скобках.it— текущий элемент списка.
Защита от null
Самая частая ошибка в старых Android-приложениях — NullPointerException: программа обращается к значению, которого нет, и падает. Kotlin защищает от неё ещё при компиляции.
Обычный тип не может хранить null. Если значения может не быть, к типу добавляют знак вопроса:
val name: String = null // ошибка компиляции
val comment: String? = null // можно: комментария может не быть
С таким значением Kotlin не даст работать напрямую. Есть безопасные операторы:
println(comment?.length) // null: метод не вызван
println(comment?.length ?: 0) // 0: запасное значение
null
0
?.вызывает метод, только если значение неnull, иначе возвращаетnull;?:(его называют «оператор Элвис») подставляет значение на случайnull.
Есть ещё !! — «я уверен, что здесь не null». Если ошибётесь, приложение упадёт. Новичкам лучше его избегать.
Попробуйте сами. Код на Kotlin можно запускать в браузере в официальной песочнице play.kotlinlang.org. Напишите функцию describe(p: Product, note: String?): String, которая возвращает «Хлеб — 1 шт.» и добавляет примечание в скобках, если оно есть: «Молоко — 2 шт. (без лактозы)».
Решение
data class Product(val name: String, val count: Int)
fun describe(p: Product, note: String?): String {
val base = "${p.name} — ${p.count} шт."
return if (note != null) "$base ($note)" else base
}
fun main() {
println(describe(Product("Хлеб", 1), null))
println(describe(Product("Молоко", 2), "без лактозы"))
}
Хлеб — 1 шт.
Молоко — 2 шт. (без лактозы)
После проверки note != null Kotlin сам понимает, что внутри ветки значение точно есть, и разрешает использовать его как обычную строку. Это называется умным приведением типа.
Мини-тест: проверьте себя
Закрепите урок: несколько вопросов, разбор ответов — в конце.
-
Чем val отличается от var?
val — неизменяемая ссылка, var — изменяемая. В Kotlin принято по умолчанию писать val, а var — только когда значение действительно меняется.
-
Что выведет println("Товаров: ${items.size}"), если в списке items три элемента?
Внутри строки $ подставляет значение. Для выражения сложнее имени переменной используют фигурные скобки: ${items.size}.
-
val name: String = null — что скажет Kotlin?
Обычный тип в Kotlin не может хранить null. Если значения может не быть, тип пишут со знаком вопроса: String?.
-
Что вернёт выражение comment?.length ?: 0, если comment равен null?
?. не вызывает length у null и возвращает null, а оператор ?: подставляет запасное значение — 0.