Ranges

range 表达式是通过 rangeTo 函数形成的。rangeTo 函数拥有形如 .. 的操作符,该操作符是用 in 和 !in 实现的。 Range 可以对任何可比较的类型做操作,但对整数基本类型是优化过的。下面是些例子:

  1. if (i in 1..10) {
  2. println(i)
  3. }
  4. if (x !in 1.0..3.0) println(x)
  5. if (str in "island".."isle") println(str)

数字的范围有个附加的特性:它们可以迭代。编译器会把它转成类似于 java 的 for 循环的形式,且不用担心越界:

  1. for (i in 1..4) print(i) // prints "1234"
  2. for (i in 4..1) print(i) // prints nothing
  3. for (x in 1.0..2.0) print("$x ") // prints "1.0 2.0 "

如果你想迭代数字并想反过来,这个相当简单,你可以使用 downTo() 函数

  1. for (i in 4 downTo 1) print(i)

也可以使用指定步数的迭代,这个用到 step()

  1. for (i in 1..4 step 2) print(i) // prints "13"
  2. for (i in 4 downTo 1 step 2) print(i) // prints "42"
  3. for (i in 1.0..2.0 step 0.3) print("$i ") // prints "1.0 1.3 1.6 1.9 "

工作原理

在标准库中有俩种接口:Range 和 Progression

Range 表示数学范围上的一个间隔。它有俩个端点:start 和 end 。主要的操作符是 contains 通常在 in/!in 操作符内:

Progression 表示一个算数级数。它有一个 start 和 end 以及一个非零 increment 。Progression 是Iterable 的一个子类,因此可以使用在 for 循环中,或者 map filter 等等。第一个元素是 start 下一个元素都是前一个元素的 increment 。Progression 的迭代与 java/javaScript 的 for 循环相同:

  1. // if increment > 0
  2. for (int i = start; i <= end; i += increment) {
  3. // ...
  4. }
  5. // if increment < 0
  6. for (int i = start; i >= end; i += increment) {
  7. // ...
  8. }

范围指标

使用例子:

  1. // Checking if value of comparable is in range. Optimized for number primitives.
  2. if (i in 1..10) println(i)
  3. if (x in 1.0..3.0) println(x)
  4. if (str in "island".."isle") println(str)
  5. // Iterating over arithmetical progression of numbers. Optimized for number primitives (as indexed for-loop in Java).
  6. for (i in 1..4) print(i) // prints "1234"
  7. for (i in 4..1) print(i) // prints nothing
  8. for (i in 4 downTo 1) print(i) // prints "4321"
  9. for (i in 1..4 step 2) print(i) // prints "13"
  10. for (i in (1..4).reversed()) print(i) // prints "4321"
  11. for (i in (1..4).reversed() step 2) print(i) // prints "42"
  12. for (i in 4 downTo 1 step 2) print(i) // prints "42"
  13. for (x in 1.0..2.0) print("$x ") // prints "1.0 2.0 "
  14. for (x in 1.0..2.0 step 0.3) print("$x ") // prints "1.0 1.3 1.6 1.9 "
  15. for (x in 2.0 downTo 1.0 step 0.3) print("$x ") // prints "2.0 1.7 1.4 1.1 "
  16. for (str in "island".."isle") println(str) // error: string range cannot be iterated over

常见的接口的定义

有俩种基本接口:Range Progression

Range 接口定义了一个范围,或者是数学意义上的一个间隔。

  1. interface Range<T : Comparable<T>> {
  2. val start: T
  3. val end: T
  4. fun contains(Element : T): Boolean
  5. }

Progression 定义了数学上的级数。包括 start end increment 端点。最大的特点就是它可以迭代,因此它是 Iterable 的子类。end 不是必须的。

  1. interface Progression<N : Number> : Iterable<N> {
  2. val start : N
  3. val end : N
  4. val increment : Number
  5. }

与 java 的 for 循环类似:

  1. // if increment > 0
  2. for (int i = start; i <= end; i += increment) {
  3. // ...
  4. }
  5. // if increment < 0
  6. for (int i = start; i >= end; i += increment) {
  7. // ...
  8. }

类的实现

为避免不需要的重复,让我们先考虑一个数字类型 Int 。其它的数字类型也一样。注意这些类的实例需要用相应的构造函数来创建,使用 rangeTo() downTo() reversed() stop() 实用函数。

IntProgression 类很直接也很简单:

  1. class IntProgression(override val start: Int, override val end: Int, override val increment: Int ): Progression<Int> {
  2. override fun iterator(): Iterator<Int> = IntProgressionIteratorImpl(start, end, increment)
  3. }

IntRange 有些狡猾:它实现了 Progression<Int> Range<Int> 接口,因为它天生以通过 range 迭代(默认增加值是 1 ):

  1. class IntRange(override val start: Int, override val end: Int): Range<Int>, Progression<Int> {
  2. override val increment: Int
  3. get() = 1
  4. override fun contains(element: Int): Boolean = start <= element && element <= end
  5. override fun iterator(): Iterator<Int> = IntProgressionIteratorImpl(start, end, increment)
  6. }

ComparableRange 也很简单:

  1. class ComparableRange<T : Comparable<T>>(override val start: T, override val end: T): Range<T> {
  2. override fun contains(element: T): Boolean = start <= element && element <= end
  3. }

一些实用的函数

rangeTo()

rangeTo() 函数仅仅是调用 *Range 的构造函数,比如:

  1. class Int {
  2. fun rangeTo(other: Byte): IntRange = IntRange(this, Other)
  3. fun rangeTo(other: Int): IntRange = IntRange(this, other)
  4. }

downTo()

downTo() 扩展函数可以为任何数字类型定义,这里有俩个例子:

  1. fun Long.downTo(other: Double): DoubleProgression {
  2. return DoubleProgression(this, other, -1.0)
  3. }
  4. fun Byte.downTo(other: Int): IntProgression {
  5. return IntProgression(this, other, -1)
  6. }

reversed()

reversed() 扩展函数是给所有的 *Range*Progression 类定义的,并且它们都返回反向的级数。

  1. fun IntProgression.reversed(): IntProgression {
  2. return IntProgression(end, start, -increment)
  3. }
  4. fun IntRange.reversed(): IntProgression {
  5. return IntProgression(end, start, -1)
  6. }

step()

step() 扩展函数是给所有的 *Range*Progression 类定义的,所有的返回级数都修改了 step 值。注意 step 值总是正的,否则函数不会改变迭代的方向。

  1. fun IntProgression.step(step: Int): IntProgression {
  2. if (step <= 0) throw IllegalArgumentException("Step must be positive, was: $step")
  3. return IntProgression(start, end, if (increment > 0) step else -step)
  4. }
  5. fun IntRange.step(step: Int): IntProgression {
  6. if (step <= 0) throw IllegalArgumentException("Step must be positive, was: $step")
  7. return IntProgression(start, end, step)
  8. }