# 范围
范围表达式是 `rangeTo` 形式的函数,它以 `..` 形式的操作符并辅以 `in` 和 `!in`。范围是为某些可比较类型而设,但对于整数原始类型会有一个优化的实现。这里是一些使用范围的示例
``` kotlin
if (i in 1..10) { // 等价于 1 <= i && i <= 10
println(i)
}
```
整数类型范围(`IntRange`、`LongRange`、`CharRange`)有一个额外的特性:它们能够被遍历。编译器会负责转换为类似的 Java 的 `for` 循环,不需要额外的开销。
``` kotlin
for (i in 1..4) print(i) // 打印 "1234"
for (i in 4..1) print(i) // 什么都不会打印
```
如果你要倒序遍历数字该怎么办?很简单,你可以使用标准库中定义的 `downTo()` 函数
``` kotlin
for (i in 4 downTo 1) print(i) // 打印 "4321"
```
有可能以任意的步长遍历数字,而不是1吗?当然了,`step()` 函数将会帮助你
``` kotlin
for (i in 1..4 step 2) print(i) // 打印 "13"
for (i in 4 downTo 1 step 2) print(i) // 打印 "42"
```
## 它如何工作
“范围”实现了库中的一个公共接口:`ClosedRange<T>`。
`ClosedRange<T>` 为可比较类型定义了一个表示数学层次中的封闭间隔。它有两个节点:包含在范围中的 `start` 和 `endInclusive`。主要的操作则是 `contains`,通常使用在形如 `in`/`!in` 操作符中。
整数类型数列(`IntProgression`、`LongProgression`、`CharProgression`)表示一个算术数列。数列通过 `first` 元素、`last`元素和一个非零 `increment` 定义。第一个元素为 `first`,接下来的元素是上一个元素的正数 `increment`。`last` 元素总是通过迭代得到,除非是空数列。
数列是 `Iterable<N>` 的一个子类型,`N` 可以分别为 `Int`、`Long` 或 `Char`,因此它能够在 `for` 循环和类似于 `map`、`filter`等函数中使用。遍历 `Progression` 等价于 Java/JavaScript 中的一个索引式 `for` 循环:
``` java
for (int i = first; i != last; i += increment) {
// ...
}
```
对于整数类型,`..` 操作符创建一个实现了 `ClosedRange<T>` 和 `*Progression` 的对象。例如,`IntRange` 实现了 `ClosedRange<Int>` 并扩展了 `IntProgression`,如此一来定义于 `IntProgression` 的所有操作对于 `IntRange` 也有效。 `downTo()` 和 `step()` 函数的结果总是一个 `*Progression`。
数列用它们里面定义的伙伴对象 `fromClosedRange` 来构建:
``` kotlin
IntProgression.fromClosedRange(start, end, increment)
```
这个数列的 `last` 元素被估算为以确定的步长 `increment` 所查找到的不大于 `end` 的最大值或以负数步长 `increment` 不小于 `end` 的最小值,相当于 `(last - first) % increment == 0`。
## 功能函数
### `rangeTo()`
整数类型上的 `rangeTo()` 操作符简单地调用 `*Range` 类的构造器,例如:
``` kotlin
class Int {
//...
operator fun rangeTo(other: Long): LongRange = LongRange(this, other)
//...
operator fun rangeTo(other: Int): IntRange = IntRange(this, other)
//...
}
```
浮点数(`Double`、`Float`)未定义它们的 `rangeTo` 操作符,但它通过标准库提供的普通 `Comparable` 类型代替使用:
``` kotlin
public operator fun <T: Comparable<T>> T.rangeTo(that: T): ClosedRange<T>
```
通过这个函数返回的范围不能用于迭代。
### `downTo()`
`downTo()` 扩展函数为某些成对的整数类型定义,这里是两个示例:
``` kotlin
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()`
`reversed()` 扩展函数为每个 `*Progression` 类所定义,并且它们全都返回颠倒的数列。
``` kotlin
fun IntProgression.reversed(): IntProgression {
return IntProgression.fromClosedRange(last, first, -increment)
}
```
### `step()`
`step()` 扩展函数为 `*Progression` 类所定义,它们都返回带有已修改的步长值 `step` 的数列,这个步长值必须始终确定,所以这个函数从不改变迭代方向。
``` kotlin
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 - first) % increment == 0` 不变,返回的数列的 `last` 值可以变得跟原来的数列不一样。这里是一个示例:
``` kotlin
(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]
```