You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何Kotlin Sequence变量捕获会导致执行结果出现差异?

Kotlin Sequence中Lambda捕获导致素数生成结果异常的原因

在素数生成的代码中,将prime变量从while循环内部移到外部声明后,Sequence的输出结果完全不符合预期。这背后的核心原因是Lambda对变量的捕获机制以及Sequence的惰性求值特性共同作用导致的。

正常代码(正确生成素数)

val primes: Sequence<Int> = sequence {
    var numbers = generateSequence(2) { it + 1 }

    while (true) {
        val prime = numbers.first()
        yield(prime)
        numbers = numbers.drop(1)
            .filter {
                it % prime != 0
            }
    }
}
println(primes.take(10).toList()) // [2, 3, 5, 7, 11, 13, 17, 19, 23, 29]

问题代码(生成结果不符合预期)

val primes: Sequence<Int> = sequence {
    var numbers = generateSequence(2) { it + 1 }
    var prime: Int
    while (true) {
        prime = numbers.first()
        yield(prime)
        numbers = numbers.drop(1)
            .filter {
                it % prime != 0
            }
    }
}
println(primes.take(10).toList()) // [2, 3, 5, 6, 7, 8, 9, 10, 11, 12]

关键差异分析

  • 变量捕获的本质不同
    • 正常代码中,prime是while循环内的val变量:每次循环都会创建一个全新的不可变变量,filter中的Lambda捕获的是当前循环这个prime的具体值。由于val不可变,即便Sequence是惰性求值,后续filter执行时引用的还是当初捕获的那个素数(比如第一次循环的2、第二次的3),能正确过滤非素数。
    • 问题代码中,prime是while循环外的var变量:Lambda捕获的是这个变量的引用而非当前值。当后续Sequence迭代触发filter逻辑时,prime已经被后续循环重新赋值为新的数值(比如第一次循环后变成3、第二次变成5),导致filter判断时用的是最新的prime值,而非创建filter时对应的素数,过滤逻辑完全失效。
  • Sequence的惰性求值放大了问题
    Kotlin Sequence的中间操作(如filter)不会立即处理元素,只有终端操作(如take(10).toList())触发时才会逐个迭代执行逻辑。这让问题代码中Lambda的执行时机被延迟,正好赶上prime变量被多次修改,最终导致结果异常。

内容的提问来源于stack exchange,提问作者yellowsymphony

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.01 21:50:38