Kotlin Reference: Ranges
可以使用 rangeTo()
函数(对应操作符为 ..
)编写区间表达式(Range Expression),并使用 in
和 !in
来补充。区间可以用于所有可比较的类型,但对于整型基本类型(Integral Primitive Type)的实现有优化。下面是一些使用区间的例子:
[code lang=”kotlin”]if (i in 1..10) { // equivalent of 1 <= i && i <= 10
println(i)
}[/code]
整型区间(IntRange
、LongRange
、CharRange
)有一个额外的功能:它们可以被迭代。编译器会把迭代转换为类似 Java 中基于索引的 for
循环的形式,不会带来额外开销。
[code lang=”kotlin”]for (i in 1..4) print(i) // prints “1234”
for (i in 4..1) print(i) // prints nothing[/code]
逆序迭代一组数字也很简单,可以使用标准库中的 downTo()
函数:
[code lang=”kotlin”]for (i in 4 downTo 1) print(i) // prints “4321”[/code]
如果想用 1 以外的任意步长来迭代数字,可以使用 step()
函数:
[code lang=”kotlin”]for (i in 1..4 step 2) print(i) // prints “13”
for (i in 4 downTo 1 step 2) print(i) // prints “42”[/code]
使用 until
函数可以创建不包含结尾元素的区间:
[code lang=”kotlin”]for (i in 1 until 10) { // i in [1, 10), 10 is excluded
println(i)
}[/code]
How it works
区间实现了库中的一个公共接口:ClosedRange<T>
。
ClosedRange<T>
表示数学意义上的闭区间,用于可比较类型。它有两个端点,start
和 endInclusive
,二者都包含在区间内。它主要的操作为 contains
,通常以 in
/ !in
操作符的形式使用。
整型数列(IntProgression
、LongProgression
、CharProgression
)表示数学上的等差数列,数列由首元素(first
)、尾元素(last
)和一个非零的步长(step
)定义。第一个元素是 first
,后续元素是前一个元素加上 step
,last
元素总会在迭代中出现,除非数列是空的。
数列是 Iterable<N>
的子类,这里的 N
是 int
、Long
或 Char
。所以数列可以用于 for 循环和 map
、filter
等函数。对 Progression
进行迭代等同于 Java / JavaScript 中的基于索引的 for 循环:
[code lang=”java”]for (int i = first; i != last; i += step) {
// …
}[/code]
对于整型类型,..
操作符会创建一个实现了 ClosedRange<T>
并继承了 *Progression
的对象。比如 IntRange
实现了 ClosedRange<Int>
并继承了 IntProgression
,因此适用于 IntProgression
的操作也适用于 IntRange
。downTo()
和 step()
的结果始终是 *Progression
。
通过在数列的伴生对象中定义的 fromClosedRange
函数来构造数列:
[code lang=”kotlin”]IntProgression.fromClosedRange(start, end, step)[/code]
数列中的 last
元素是计算得到的,满足 (last - first) % step == 0
:对于正的 step
,last
的值为满足条件的不大于 end
的最大值,;对于负的 step
,last
的值为满足条件的不小于 end
的最小值。
Utility functions
rangeTo()
rangeTo()
操作符用于整型类型上时,只是简单地调用了对应 *Range
类的构造器,如:
[code lang=”kotlin”]class Int {
//…
operator fun rangeTo(other: Long): LongRange = LongRange(this, other)
//…
operator fun rangeTo(other: Int): IntRange = IntRange(this, other)
//…
}[/code]
浮点类型数字(Double
、Float
)没有定义自己 rangeTo
操作符,而是使用标准库为泛用 Comparable
类型提供的 rangeTo
作为替代:
[code lang=”kotlin”]public operator fun
该函数返回的区间不能用于迭代。
downTo()
对于任意两个整型类型的组合,都有对应的 downTo()
扩展函数,如下面的两个例子:
[code lang=”kotlin”]fun Long.downTo(other: Int): LongProgression {
return LongProgression.fromClosedRange(this, other.toLong(), -1L)
}
fun Byte.downTo(other: Int): IntProgression {
return IntProgression.fromClosedRange(this.toInt(), other, -1)
}[/code]
reversed()
对于每一个 *Progression
类,都定义了 reversed()
扩展函数,用于返回逆序的数列。
[code lang=”kotlin”]fun IntProgression.reversed(): IntProgression {
return IntProgression.fromClosedRange(last, first, -step)
}[/code]
step()
对于每一个 *Progression
类,都定义了 step()
扩展函数,用于根据 step
(函数参数)的值返回具有对应步长的数列。步长值必须为正数,因此这个函数永远不会改变迭代的方向:
[code lang=”kotlin”]fun IntProgression.step(step: Int): IntProgression {
if (step <= 0) throw IllegalArgumentException(“Step must be positive, was: $step”)
return IntProgression.fromClosedRange(first, last, if (this.step > 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, if (this.step > 0) step else -step)
}[/code]
需要注意的是,为了保证不变式 (last - first) % step == 0
,该函数返回数列的 last
可能会与原数列的 last
不同,例如:
[code lang=”kotlin”](1..12 step 2).last == 11 // progression with values [1, 3, 5, 7, 9, 11]
(1..12 step 3).last == 10 // progression with values [1, 4, 7, 10]
(1..12 step 4).last == 9 // progression with values [1, 5, 9][/code]