Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

循环与范围

for 关键字用于对序列中的每个值执行一系列代码块。

值的集合可以是整数范围、String,或者在本书后面将会介绍的项目集合。in 关键字表示你正在遍历值:

for (v in values) {
  // 使用 v 做一些操作
}

每次循环迭代,v 都会被赋予 values 中的下一个元素。

下面是一个 for 循环,重复一个动作固定次数:

// LoopingAndRanges/RepeatThreeTimes.kt

fun main() {
  for (i in 1..3) {
    println("Hey $i!")
  }
}
/* 输出:
Hey 1!
Hey 2!
Hey 3!
*/

输出显示索引 i 接收了范围从 1 到 3 的每个值。

范围是由一对端点定义的值间隔。有两种基本方法来定义范围:

// LoopingAndRanges/DefiningRanges.kt

fun main() {
  val range1 = 1..10         // [1]
  val range2 = 0 until 10    // [2]
  println(range1)
  println(range2)
}
/* 输出:
1..10
0..9
*/
  • [1] 使用 .. 语法会将两个边界都包含在结果范围内。
  • [2] until 排除了结束点。输出显示 10 不是范围的一部分。

显示范围会生成可读性良好的格式。

下面的代码将从 10 到 100 的数字求和:

// LoopingAndRanges/SumUsingRange.kt

fun main() {
  var sum = 0
  for (n in 10..100) {
    sum += n
  }
  println("sum = $sum")
}
/* 输出:
sum = 5005
*/

你可以以相反的顺序遍历范围。你还可以使用 step 值来改变默认的间隔值 1

// LoopingAndRanges/ForWithRanges.kt

fun showRange(r: IntProgression) {
  for (i in r) {
    print("$i ")
  }
  print("    // $r")
  println()
}

fun main() {
  showRange(1..5)
  showRange(0 until 5)
  showRange(5 downTo 1)          // [1]
  showRange(0..9 step 2)         // [2]
  showRange(0 until 10 step 3)   // [3]
  showRange(9 downTo 2 step 3)
}
/* 输出:
1 2 3 4 5     // 1..5
0 1 2 3 4     // 0..4
5 4 3 2 1     // 5 downTo 1 step 1
0 2 4 6 8     // 0..8 step 2
0 3 6 9     // 0..9 step 3
9 6 3     // 9 downTo 3 step 3
*/
  • [1] downTo 生成递减范围。
  • [2] step 改变了间隔。在这里,范围的步长为 2,而不是默认的 1。
  • [3] until 也可以与 step 一起使用。注意这如何影响输出。

在每种情况下,数字序列形成一个等差数列。showRange() 接受一个 IntProgression 参数,这是一种内置类型,包括了 Int 范围。注意,每行输出的注释中出现的 IntProgressionString 表示形式通常与传递给 showRange() 的范围不同 - IntProgression 将输入转化为一个等效的常见形式。

你还可以生成一个字符范围。以下 for 循环从 a 遍历到 z

// LoopingAndRanges/ForWithCharRange.kt

fun main() {
  for (c in 'a'..'z') {
    print(c)
  }
}
/* 输出:
abcdefghijklmnopqrstuvwxyz
*/

你可以遍历整数和字符等整数量的元素范围,但不能遍历浮点数值。

使用方括号可以通过索引访问字符。因为在 String 中我们从零开始计算字符,所以 s[0] 会选择 String s 的第一个字符。选择 s.lastIndex 会产生最后一个索引号:

// LoopingAndRanges/IndexIntoString.kt

fun main() {
  val s = "abc"
  for (i in 0..s.lastIndex) {
    print(s[i] + 1)
  }
}
/* 输出:
bcd
*/

有时候人们将 s[0] 描述为“第零个字符”。

字符存储为与其 ASCII 代码 对应的数字,因此将整数添加到字符会产生一个新的字符,其对应新的代码值:

// LoopingAndRanges/AddingIntToChar.kt

fun main() {
  val ch: Char = 'a'
  println(ch + 25)
  println(ch < 'z')
}
/* 输出:
z
true
*/

第二个 println() 显示你可以比较字符代码。

for 循环可以直接遍历 String

// LoopingAndRanges/IterateOverString.kt

fun main() {
  for (ch in "Jnskhm ") {
    print(ch + 1)
  }
}
/* 输出:
Kotlin!
*/

ch 依次接收每个字符。

在下面的示例中,函数 hasChar() 遍历字符串 s 并测试它是否包含给定的字符 ch。在函数中间的 return 在答案找到时停止函数:

// LoopingAndRanges/HasChar.kt

fun hasChar(s: String, ch: Char): Boolean {
  for (c in s) {
    if (c == ch) return true
  }
  return false
}

fun main() {
  println(hasChar("kotlin", 't'))
  println(hasChar("kotlin", 'a'))
}
/* 输出:
true
false
*/

下一部分将展示 hasChar() 是不必要的,你可以使用内置的语法来替代。

如果你只是想要重复一个动作固定次数,可以使用 repeat() 替代 for 循环:

// LoopingAndRanges/RepeatHi.kt

fun main() {
  repeat(2) {
    println("hi!")
  }
}
/* 输出:
hi!
hi!
*/

repeat() 是标准库函数,不是关键字。你将在本书后面看到它是如何被创建的。

练习和解答可在 www.AtomicKotlin.com 找到。