# 范圍
范圍表達式是 `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]
```