我正在将一些代码从Scala迁移到Kotlin,我观察到不同的行为:

规模:以下步骤:

var i = 0

Iterator.continually{
  println(s"i=$i")
  i += 1
  i
}.takeWhile { 
  _ < 3
}.foreach { i =>
  println(s"I=$i")
}

输出:


Console (F3)

i=0
I=1
i=1
I=2
i=2

Kotlin类似功能:

fun <A> continousIterator(func: () -> A): Iterable<A> =
    object: Iterable<A> {
        override fun iterator() =
            object: Iterator<A> {
                override fun hasNext(): Boolean = true
                override fun next(): A = func()
            }
    }
    
var i = 0;
    
fun main() {
    continousIterator{
        println("i=$i")
        i += 1
        i
    }.takeWhile{
      it < 3
    }.forEach { 
      println("I=$it")
    }
}

输出:

i=0
i=1
i=2
I=1
I=2

当我们有状态时,结果不同,func()iterator的调用顺序不同.

我想知道为什么.

推荐答案

在Kotlin中,当调用takeWhile时,takeWhile立即遍历序列并打印0到2,并生成List.只有在这之后,forEach才会运行,打印1和2.

要复制Scala行为,您需要forEach来使用序列,而不是takeWhile.Sequence可以做到这一点:

generateSequence {
    println("i=$i")
    i += 1
    i
}.takeWhile{it < 3}.forEach { println("I=$it")}

Sequence的操作都是懒惰的.除非绝对必要,否则它们不会使用该序列.

Kotlin相关问答推荐

如何在Kotlin中反射多个对象以查找特定类型的属性

如何在Jetpack Compose中从领域查询中读取数据?

我需要后台工作才能使用卡夫卡的消息吗?

如何创建一个空的kotlin工作?

如何使用 Kotlin Maven 更改 Minecraft 插件中的 Shulker GUI 标题

kotlin 父类具有依赖于抽象变量的变量

如何在 Kotlin 中声明一个空数组而不期望 null?

如何将 `throw` 放置在辅助函数中但仍然具有空安全性?

Jetpack Compose:当状态从另一个活动改变时强制重组

Kotlin 使用迭代索引过滤 lambda 数组

listOf() 返回 MutableList

参考 Kotlin 中的 Java 接口静态字段

在 Kotlin 中,当枚举类实现接口时,如何解决继承的声明冲突?

将 Gradle 子元素与 Kotlin 多平台一起使用

Kotlin 解构超过五个组件

使用 Paging 3 时保存并保留 LazyColumn 滚动位置

@uncheckedVariance 在 Kotlin 中?

在kotlin中,如何模拟封装回调函数?

如何在Kotlin中将字符串转换为InputStream?

Kotlin 错误:public function exposes its 'public/*package*/' return type argument