type | layout | category | title | url |
---|---|---|---|---|
doc |
reference |
Syntax |
Интервалы |
Интервалы оформлены с помощью функций rangeTo
и имеют оператор в виде ..
, который дополнятся in и !in.
Они применимы ко всем сравниваемым (comparable) типам, но для целочисленных примитивов есть оптимизированная реализация. Вот несколько примеров применения интервалов.
if (i in 1..10) { // equivalent of 1 <= i && i <= 10
println(i)
}
Интервалы целочисленного типа (IntRange
, LongRange
, CharRange
) имеют определённое преимущество: они могут иметь дополнительную итерацию.
Компилятор конвертирует такие интервалы в аналогичные циклы for из языка Java.
for (i in 1..4) print(i) // prints "1234"
for (i in 4..1) print(i) // prints nothing
А что, если вы хотите произвести итерацию в обратном порядке? Это просто. Можете использовать функцию downTo()
, определённую в стандартной библиотеке.
for (i in 4 downTo 1) print(i) // prints "4321"
А есть ли возможность производить итерацию с шагом, отличным от еденицы? Разумеется. В этом вам поможет функция step()
:
for (i in 1..4 step 2) print(i) // prints "13"
for (i in 4 downTo 1 step 2) print(i) // prints "42"
Для создания интервала, который не включает последний элемент перебора, используйте until
:
for (i in 1 until 10) { // i in [1, 10), 10 is excluded
println(i)
}
Интервалы реализуют интерфейс ClosedRange<T>
.
Говоря математическим языком, интерфейс ClosedRange<T>
обозначет ограниченный отрезок и предназначен для типов, подлежащих сравнению.
У него есть две контрольные точки: start
и endInclusive
. Главной операцией является contain
. Чаще всего она используется вместе с операторами in/!in.
Целочисленные последовательности (IntProgression
, LongProgression
, CharProgression
) являются арифметическими.
Последовательности определены элементами first
, last
и ненулевым значением increment
.
Элемент first
является первым, последующими являются элементы, полученные при инкрементации предыдущего элемента с помощью increment
. Если последовательность не
яаляется пустой, то элемент last
всегда достигается в результате инкрементации.
Последовательность является подтипом Iterable<N>
, где N
- это Int
, Long
или Char
. Таким образом, её можно использовать в циклах for и функциях типа map
, filter
и т.п.
Итерация Progression
идентична проиндексованному циклу for в Java/JavaScript
for (int i = first; i != last; i += increment) {
// ...
}
Для целочисленных типов, оператор ..
создаёт объект, который реализует в себе ClosedRange<T>
и *Progression*
.
К примеру, IntRange
наследуется от класса IntProgression
и реализует интерфейс ClosedRange<Int>
. Поэтому все операторы, обозначенные для IntProgression
, также доступны и для
IntRange
. Результатом функций downTo()
и step()
всегда будет *Progression*
(перев.: последовательность).
Последовательности спроектированы с использованием функции fromClosedRange
в их вспомогательном объекте (companion object):
IntProgression.fromClosedRange(start, end, increment)
Для нахождения максимального значения в прогрессии вычисляется элемент last
. Для последовательности с положительным инкрементом этот элемент вычисляется так, чтобы он был не больше
элемента end
. Для тех последовательностей, где инкремент отрицательный - не меньше.
Операторы rangeTo()
для целочисленных типов просто вызывают конструктор класса *Range*
:
class Int {
//...
operator fun rangeTo(other: Long): LongRange = LongRange(this, other)
//...
operator fun rangeTo(other: Int): IntRange = IntRange(this, other)
//...
}
Числа с плавающей точкой (Double
, Float
) не имеют своего оператора rangeTo
. Такой оператор обозначен для них в дженериках типа Comparable
стандартной библиотеки:
public operator fun <T: Comparable<T>> T.rangeTo(that: T): ClosedRange<T>
Интервал, полученный с помощью такой функции, не может быть использован для итерации.
Экстеншн-функция downTo()
задана для любой пары целочисленных типов, вот два примера:
fun Long.downTo(other: Int): LongProgression {
return LongProgression.fromClosedRange(this, other, -1.0)
}
fun Byte.downTo(other: Int): IntProgression {
return IntProgression.fromClosedRange(this, other, -1)
}
Функция reversed()
расширяет класс *Progression*
таким образом, что все экземпляры этого класса возвращают обратные последовательности при её вызове.
fun IntProgression.reversed(): IntProgression {
return IntProgression.fromClosedRange(last, first, -increment)
}
Функция-расширение step()
также определена для классов *Progression*
,
возвращает последовательность с изменённым значением шага step
(параметр функции).
Значение шага всегда должно быть положительным числом для того, чтобы функция никогда не меняла направления своей итерации.
fun IntProgression.step(step: Int): IntProgression {
if (step <= 0) throw IllegalArgumentException("Step must be positive, was: $step") //шаг должен быть положительным
return IntProgression.fromClosedRange(first, last, if (increment > 0) step else -step)
}
fun CharProgression.step(step: Int): CharProgression {
if (step <= 0) throw IllegalArgumentException("Step must be positive, was: $step")
return CharProgression.fromClosedRange(first, last, step)
}
Обратите внимание, что значение элемента last
в возвращенной последовательности может отличаться от значения last
первоночальной последовательности с тем,
чтобы предотвратить инвариант (last - first) % increment == 0
. Вот пример:
(1..12 step 2).last == 11 // последовательность чисел со значениями [1, 3, 5, 7, 9, 11]
(1..12 step 3).last == 10 // последовательность чисел со значениями [1, 4, 7, 10]
(1..12 step 4).last == 9 // последовательность чисел со значениями [1, 5, 9]