Освой Kotlin играючи
/* Моя кошка замечательно разбирается в программировании. Стоит мне объяснить проблему ей - и все становится ясно. */
John Robbins, Debugging Applications, Microsoft Press, 2000
В Kotlin есть уникальные типы, которые вы не встречали в Java. Уверен, вам понравится.
Интерфейс ClosedRange<T> с методом rangeTo() позволяет быстро и элегантно создавать интервалы от начального до конечного значения, который является частью диапазона. На его основе созданы специальные типы IntRange, LongRange, CharRange.
Метод rangeTo() имеет операторную форму .. и может сопровождаться операторами in и !in.
Рассмотрим простой пример.
val oneToFive = 1..5
println(oneToFive::class.java) // возвращает class kotlin.ranges.IntRange
Выражение 1..5 можно заменить:
val oneToFive = IntRange(1, 5)
println(oneToFive) // 1..5
Альтернативная версия. Заодно покажу пример с символами.
val oneToFive: IntRange = 1.rangeTo(5)
// CharRange
val characters = 'a'.rangeTo('z') // all letters from 'a' to 'z'
Выберем случайное число из диапазона от 1 до 6 (игральный кубик).
val diceRange = 1..6
val randomNumber = diceRange.random()
println("Random number: ${randomNumber}")
println(diceRange::class)
Тип IntRange и его родственники имеют сверхспособности - проходить циклически по всем элементам. И это очень удобно.
Мы уже знакомились с оператором in в цикле for. Но он может быть использован и отдельно в функции. Например, мы можем проверить, входит ли символ в диапазон символов русского алфавита от символа к до символа т. Символ о точно попадёт в заданный диапазон, а также символы Л, М, Н и т.д.
fun isCat(c: Char) = c in 'к'..'т' || c in 'К'..'Т'
// проверяем символы в нижнем и верхнем регистрах
println(isCat('о'));
Пример с числами.
val number = 5 // проверим, входит ли число в заданный диапазон
println(number in 1..100) // true
Интервалы помогают сократить количество кода и улучшить читаемость.
// много кода
if (i >= 0 && i <= 10)
println(i)
// меньше кода
if (i in 0..10)
println(i)
По умолчанию, интервалы увеличиваются от меньшего к большему. Если нужно изменить порядок, то используйте downTo. Если нужно изменить шаг, то используйте ключевое слово step. Примеры показаны в for.
Очень часто в циклах встречается выражение size - 1, чтобы не выйти за пределы массива. Можно заменить на until, чтобы не использовать последний элемент интервала. Примеры показаны в for.
В Kotlin есть несколько готовых функций для работы с интервалами. Например, coerceIn(), вы задаёте интервал, если число не входит в него, то берётся минимальное или максимальное значение интервала.
fun showProgress(progress: Int){
val percent = progress.coerceIn(0, 100)
println("We're ${percent}% done")
}
showProgress(45) // 45
showProgress(105) // 100
Узнать минимальное, максимальное значение интервала, а также сумму всех чисел в интервале можно через соответствующие функции.
val intRange: IntRange = 3..7
val min = intRange.minOrNull()
val max = intRange.maxOrNull()
val sum = intRange.sum()
println("Min: $min; Max: $max; Sum: $sum") // Min: 3; Max: 7; Sum: 25
Выбрать случайный элемент из интервала можно через random().
val charRange: CharRange = 'a'..'c'
val randomChar = charRange.random()
println(randomChar) // 'a' or 'b' or 'c'
Несколько классов для интервалов позволяют работать с элементами интервала просто и быстро. Пример для класса IntProgression.
val progression: IntProgression = 0..100 step 10
for (i in progression) {
println(i)
}
/*
0
10
20
30
40
50
60
70
80
90
100
*/
Узнать величину шага step (в том числе значение по умолчанию, когда step не используется в явном виде) можно через соответствующие свойства.
val intProgression = 1..450 step 10
val intStep = intProgression.step
println(intStep) // 10
val longProgression = 10L downTo 1L
val longStep = longProgression.step
println(longStep) // -1
val charProgression = 'a'..'z'
val charStep = charProgression.step
println(charStep) // 1
Указав нужный интервал, можно перечислить его элементы в обратном порядке через метод reversed():
val fate: IntRange = 1..9
for (life in fate.reversed()) {
println("Remaining lives: " +
"$life")
}
Получим ответ.
Remaining lives: 9
Remaining lives: 8
Remaining lives: 7
Remaining lives: 6
Remaining lives: 5
Remaining lives: 4
Remaining lives: 3
Remaining lives: 2
Remaining lives: 1
Для объектов классов Range и Progression доступны свойства first и last, позволяющие узнать первые и последние элементы интервалов.
val intRange = 1..9
val first = intRange.first
println(first)
val progression: IntProgression = 0..100 step 10
println(progression.first)
Продвинутые программисты могу создать собственные интервалы на основе Range и Progression.