Kotlin学习总结:Kotlin基础(四)
Kotlin学习总结:Kotlin基础(四)
迭代事物:“while”循环和“for”循环
在Kotlin中for循环仅以唯一一种形式存在,和Java的for-each循环一致。其写法for<item> in <elements>和C#一样。和Java一样,循环最常见的应用就是迭代集合。
迭代数字:区间和数列
在Kotlin中没有常规的Java for循环。在这种循环中,先初始化变量,在循环的每一步更新它的值,并在值满足某个限制条件时退出循环。为了替代这种最常见的循环用法,Kotlin使用了区间的概念。
区间本质上就是两个值之间的间隔,这两个值通常是数字:一个起始值,一个结束值。使用…运算符来表示区间:
val oneToTen = 1..10
注意Kotlin的区间是包含的或者是闭合的,意味着第二个值始终是区间的一部分。
能用整数区间做的最基本的事情就是循环迭代其中所有的值。如果能迭代区间中所有的值,这样的区间被称作数列。
用整数迭代来玩Fizz-Buzz游戏。游戏玩家轮流递增计数,遇到能被3整除的数字就用单词fizz代替,遇到能被5整除的数字则用单词buzz代替。如果一个数字是3和5的公倍数,你得说“FizzBuzz”。
使用when实现Fizz-Buzz游戏:
fun fizzBuzz(i: Int) =
when {
i % 15 == 0 -> "FizzBuzz " // 如果i能被15整除,返回FizzBuzz。和Java一样%是取模运算符
i % 3 == 0 -> "Fizz " // 如果i能被3整除,返回Fizz
i % 5 == 0 -> "Buzz " // 如果i能被5 整除,返回Buzz
else -> "$i " // 否则返回数字自己
}
1 2 Fizz 4 Buzz Fizz 7 ...
把游戏变得复杂一点:从100开始倒着计数并且只计偶数。
迭代带步长的区间:
>>> for (i in 1..100){ // 在整数区间1.。100迭代
··· print(fizzBuzz(i))
··· }
Buzz 98 Fizz 94 92 FizzBuzz 88 ...
现在在迭代一个带步长的数列,它允许跳过一些数字。步长也可以是负数,这种情况下数列是递减而不是递增的。
…语法始终创建的是包含结束值(…右边的值)的区间。许多情况下,迭代不包含指定结束值的半闭合区间更方便。使用until函数可以创建这样的区间。例如for (x in 0 until size)虽然等同于for ( x in 0…size - 1),但是更清晰地表达了意图。
迭代map
使用for…in循环地最常见地场景是迭代集合。这和Java中的用法一样,接下来迭代map。
实现一个打印字符二进制表示的小程序。会把这些二进制表示保存在一个map中(仅做说明值用)。下面的代码创建了一个map,把某些字母的二进制表示填充进去,最后打印出map的内容。
初始化并迭代map:
val binaryReps = TreeMap<Char, String>() // 使用TreeMap让键排序
fun main() {
for (c in 'A'..'F'){ // 使用字符区间迭代从A到F之间的字符
val binary = Integer.toBinaryString(c.toInt()) // 把ASCII码转换成二进制
binaryReps[c] = binary // 根据键c把值存储到map中
}
for ((letter, binary) in binaryReps) { // 迭代map,把键和值赋给两个变量
println("$letter = $binary")
}
}
…语法不仅可以创建数字区间,还可以创建字符区间。
上面的代码展示了for循环允许展开迭代中的集合的元素(在这个例子中,展开的是map的键值对集合)。把展开的结果存储到了两个独立的变量中:letter是键,binary是值。可以使用map[key]读取值,并使用map[key] = value设置它们,而不需要调用get和put。下面这段代码
binaruyReps[c] = binary
等价于它的Java版本
binaryReps.put(c, binary)
例子的输出:
A = 1000001
B = 1000010
C = 1000011
D = 1000100
E = 1000101
F = 1000110
可以用这样的展开语法在迭代集合的同时跟踪当前项的下标。不需要创建一个单独的变量来存储下标并手动增加它:
val list = arrayListOf("10", "11", "1001")
for ((index, element) in list.withIndex()) { // 迭代集合时使用下标
println("$index:$element")
}
这段代码打印的内容:
0:10
1:11
2:1001
使用“in”检查集合和区间的成员
使用in运算符来检查一下一个值是否在区间中,或者它的逆运算,!n,来检查这个值是否不在区间中。下面展示了如何使用in来检查一个字符是否属于一个字符区间。
使用in检查区间的成员
fun isLetter(c: Char) = c in 'a'..'z' || c in 'A' ..'Z'
fun isNotDigit(c: Char) = c !in '0'..'9'
>>> println(isLetter('q'))
true
>>> println(isNotDigit('x'))
true
这种检查字符是否是英文字母的技巧看起来很简单。在底层,没有什么特别处理:依然会检查字符的编码是否位于第一个字母编码和最后一个字母编码之间的某个位置。但是这个逻辑被简洁地隐藏到了标准库中地区间类实现中:
c in 'a'..'z' // 变换成a <= c && c <= z
in运算符和!in也适用于when表达式。
用in检查作为when分支:
fun recognize(c: Char) =
when (c) {
in '0'..'9' -> "It's a digit!" // 检查值是否在0到9之间
in 'a'..'z', in 'A'..'Z' -> "It's a letter" // 可以组合多种区间
else -> "I don't know..."
}
>>> println(recognize('8'))
It's a digit!
区间也不仅限于字符。假如有一个支持实例比较操作的任意类(实现了Java.lang.Comparable接口),就能创建这种类型的区间。如果是这样的区间,并不能列举出这个区间中的所有对象。