Kotlin 操作符 in 的基本使用(十)
导读大纲
- 1.0.1 迭代集合
- 1.0.2 使用 in 检查集合和范围
1.0.1 迭代集合
-
使用 for (x in y) 循环最常见的情况是对一个集合进行迭代
- 您很可能已经熟悉它的行为–对输入集合中的每个元素都执行循环
-
在这种情况下,您只需打印颜色集合中的每个元素
- 在循环内部,单个颜色可以用 color 来表示
fun main() {
val collection = listOf("red", "green", "blue")
for (color in collection) {
print("$color ")
}
// red green blue
}
- 再举一个例子,我们将打印字符的二进制表示
- 为你提供一个简单的查找表,帮助你手动破译二进制编码文本
- 如 1000100 1000101 1000011 1000001 1000110
- 您将这些二进制表示法存储在Map中,将一些字母的二进制表示填入其中
- 然后打印Map中的内容
- <1> 可变映射保留 Kotlin 中的元素迭代顺序
- <2> 创建范围的"…"语法不仅适用于数字,也适用于字符
- 在这里,我们用它来遍历从 A 到 F的所有字符对应的二进制
- <3> 将 ASCII 码转换为二进制码
- <4> 使用 char 作为键,将值存储在映射中
- <5> 遍历映射表,将key 指定为 letter,并将对应的value指定为binary值
- 通过 for 循环,可以解包正在迭代的集合中的元素
- 本例中是 map 中的键值对集合
- 解构的结果存储在两个独立的变量中
- letter变量接收key,binary变量接收value
- 为你提供一个简单的查找表,帮助你手动破译二进制编码文本
fun main() {
val binaryReps = mutableMapOf<Char, String>() // <1>
for (char in 'A'..'F') { // <2>
val binary = char.code.toString(radix = 2) // <3>
binaryReps[char] = binary // <4>
}
for ((letter, binary) in binaryReps) { // <5>
println("$letter = $binary")
}
}
==============================================
A = 1000001
B = 1000010
C = 1000011
D = 1000100
E = 1000101
F = 1000110
-
上述示例使用的另一个妙招是按key获取和更新 map 值的简易语法
- 可以使用 map[key] 读取值,使用 map[key] = value 设置值
- 而不必调用 get 和 put 等函数,拥有Python的简洁又类型安全,怎能不学
- 这意味着无需使用 Java 风格版本的 binaryReps.put(char,binary)
- 而是可以使用等价但更优雅的 binaryReps[char] = binary
- 可以使用 map[key] 读取值,使用 map[key] = value 设置值
-
可以使用相同的解构语法来遍历一个列表
- 同时跟踪当前项的索引
- 就避免创建一个单独的变量来存储索引和手动递增索引
- <1> 将使用 withIndex 函数打印集合元素及其各自的索引
- 这样就可以避免创建一个单独的index变量来跟踪元素的索引值
- 类似Python中的: for i, elem in enumerate([1]),是不是很惊艳
- 同时跟踪当前项的索引
fun main() {
val list = listOf("10", "11", "1001")
for ((index, element) in list.withIndex()) { // <1>
println("$index: $element")
}
// 0: 10
// 1: 11
// 2: 1001
}
1.0.2 使用 in 检查集合和范围
-
还可以使用 in 操作符来检查某个值是否在某个范围内
- 或者使用其反义词"!in"来检查某个值是否不在某个范围内
-
例如,在验证用户输入时,经常需要检查输入字符是否确实是字母或不包括数字
- <1> 使用 in 编写一些小型辅助函数 isLetter 和 isNotDigit
- 以检查某个字符是否属于某个字符范围
- "c in ‘a’…‘z’"的底层工作原理仍然要
- 检查字符的序列码是否介于第一个字母的代码和最后一个字母的代码之间
- 实际上会转换为判断 “‘a’ <= c && c <= ‘z’”
- 但这一逻辑被简洁地隐藏在标准库中 range 的实现中
- 检查字符的序列码是否介于第一个字母的代码和最后一个字母的代码之间
- <1> 使用 in 编写一些小型辅助函数 isLetter 和 isNotDigit
fun isLetter(c: Char) = c in 'a'..'z' || c in 'A'..'Z' // <1>
fun isNotDigit(c: Char) = c !in '0'..'9' // <1>
fun main() {
println(isLetter('q'))
// true
println(isNotDigit('x'))
// true
}
- in 和 !in 操作符也可以在 when 表达式中使用
- when表达式真的很强大–传送门
- 当需要检查多个不同的范围时,这就更加方便
- <1> 检查数值是否在 0 到 9 的范围内
- <2> 可以合并多个范围, 即when的分支支持多个选项,以逗号分隔
fun recognize(c: Char) = when (c) {
in '0'..'9' -> "It's a digit!" // <1>
in 'a'..'z' , in 'A'..'Z' -> "It's a letter!" // <2>
else -> "I don't know..."
}
fun main() {
println(recognize('8'))
// It's a digit!
}
- 范围也不局限于字符
- 如果您有任何支持比较实例的类,通过实现 kotlin.Comparable 接口
- 就可以创建该类型对象的范围
- <1> 底层逻辑是等同于 “Java” <= “Kotlin” && “Kotlin” <= “Scala”
- 请注意,这里的字符串是按字母顺序比较的
- 因为 String 类就是这样实现 kotlin.Comparable 接口的
- 在按字母顺序排序时,"Java"排在"Kotlin"之前, 而"Kotlin"排在"Scala"之前
- 因此 “Kotlin” 位于两个字符串之间,检查结果为true
- 请注意,这里的字符串是按字母顺序比较的
- 如果您有任何支持比较实例的类,通过实现 kotlin.Comparable 接口
fun main() {
println("Kotlin" in "Java".."Scala") // <1>
// true
}
- 同样的检查方法也适用于集合
- <1> 该集合不包含 “Kotlin” 字符串,所以检查结果为false
fun main() {
println("Kotlin" in setOf("Java", "Scala")) // <1>
// false
}