Dev*_*abc 3 iteration iterator while-loop bufferedreader kotlin
某些编程语言中的常见模式是有一个函数,在调用时返回下一个值,直到到达有限序列的末尾,在这种情况下,它会一直返回 null。
Java 中的一个常见示例是这样的:
void printAll(BufferedReader reader) {
String line;
// Assigns readLine value to line, and then check if not null
while ((line = reader.readLine()) != null) {
System.out.println(line);
}
}
Run Code Online (Sandbox Code Playgroud)
它与Iterator 设计模式iterator中的 类似,但迭代器有 a和 a ,而BufferedReader没有检查功能,只有 形式,其中返回的对象可以为 null 以标记序列的结束。我调用诸如“下一个函数”(或者可能是“ yield ”函数)之类的函数,但我不知道是否有一个词来形容这种模式。next(): ObjecthasNext(): BooleanhasNext()next(): Object?next()
在 Java 中,表达式可以包含赋值,这允许如下构造:(line = reader.readLine()) != null。此代码将可为空的值赋给readLine()to line,然后检查 in 的值是否line不为空。但 Kotlin 不允许这样的构造,因为在 Kotlin 中,赋值不是表达式,因此它不能用作 Kotlin 中的循环条件。
Kotlin 中可能有哪些模式来循环 next 函数返回的有限数量的值,例如readLine()?(例如,还可以在ZipInputStream中找到 Next 函数,以转到下一个 zip 条目。)
我不仅仅是在寻找解决这个问题的 Kotlin 解决方法,因为我可以自己编程,不会出现任何问题。我正在探索可能的模式,以便人们可以选择适合自己需求的模式。
我自己发现了一些模式,我将把它们作为答案发布在这里,但可能还有更多模式,了解这些模式会很有趣。
我已按(我认为)最佳解决方案按降序排列解决方案。
generateSequence(推荐)我刚刚发现 Kotlin 有一个内置的独立generateSequence()函数(位于kotlin.sequences包中)。
generateSequence { br.readLine() }
.forEach { line ->
println("Line: $line")
}
Run Code Online (Sandbox Code Playgroud)
generateSequence接受您可以提供的代码块,该代码块必须生成一个值。在本例中,br.readLine()是代码块,并且生成一个字符串,或者如果到达末尾则生成 null。generateSequence生成一个序列,readLine()当从序列中请求下一个值时,该序列会在内部调用,直到readLine()返回 null,这会终止序列。因此 Kotlin 中的序列是惰性的:它们不会提前读取也不知道所有值,readLine()例如在forEach处理单行时仅调用一个值。这种惰性通常正是您想要的,因为它可以节省内存并最大限度地减少初始延迟。要将其更改为 eagerly,您可以generateSequence { br.readLine() }附加.toList().
generateSequence)。Sequence,因此您可以链接其他方法,例如filter().null关键字,也?没有!运算符。)IMO,这是迄今为止我见过的最干净的解决方案。
while (true) {
val line = br.readLine() ?: break
println("Line: $line")
}
Run Code Online (Sandbox Code Playgroud)
alsodo {
val line = br.readLine()?.also { line ->
println("Line: $line")
}
} while (line != null)
Run Code Online (Sandbox Code Playgroud)
next每次迭代开始前和结束时对于刚刚接触 Kotlin 的 Java 程序员来说,这可能是最常见的解决方案。
var line = br.readLine()
while (line != null) {
println("Line: $line")
line = br.readLine()
}
Run Code Online (Sandbox Code Playgroud)
readLine) 调用和重复的赋值。also这是 IntelliJ 将 Java 转换为 Kotlin 代码时生成的解决方案:
var line: String?
while (br.readLine().also { line = it } != null) {
println("Line: $line")
}
Run Code Online (Sandbox Code Playgroud)
缺点: line 被声明为可为空,即使它在循环内永远不能为空。因此,如果您想访问 的成员,则通常必须使用非空断言运算符line,您可以使用以下方法将其限制为一个断言:
var nullableLine: String?
while (br.readLine().also { nullableLine = it } != null) {
val line = nullableLine!!
println("Line: $line")
}
Run Code Online (Sandbox Code Playgroud)
请注意,如果更改var line: String?为var line: String,代码仍然可以编译,但当line变为 null 时,即使没有使用非空断言,它也会抛出 NPE。
| 归档时间: |
|
| 查看次数: |
550 次 |
| 最近记录: |