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

Kotlin实现埃氏筛问题:为何输出缺失4且混入非质数?

问题本质:闭包捕获引用而非值 + 序列懒加载的执行时机

你的错误代码中,所有filter操作里的lambda捕获的是同一个可变prime变量的引用,而非每次添加filter时prime的具体值。因为序列是懒加载的,所有filter的条件判断都要等到实际遍历序列时才执行,而此时循环已经更新了prime变量的值,导致所有filter都使用了当前(或最后一次循环)的prime值,而非各自对应的质数。

为什么会出现「缺失4,混入6、8」的现象?

举个对应错误逻辑的场景:

  1. 初始序列为2,3,4,5,6,7,8,...
  2. 第一次循环取prime=2,添加filter「it%prime !=0」,然后返回2
  3. 第二次循环取新序列的第一个元素(此时filter还未执行)得到3,更新prime=3,添加新的filter「it%prime !=0」,然后返回3
  4. 当你继续遍历取后续元素时,才会执行之前添加的所有filter:
    • 第一个filter的条件实际是「it%3 !=0」(因为prime已经被更新为3),而非你预期的「it%2 !=0」
    • 这就导致2的倍数(如6、8)不会被过滤,只要它们不是当前prime的倍数就能通过;而4这类数,可能在遍历到它时,prime已经更新为更大的值(比如3),4%3≠0本应通过,但如果你的代码逻辑中在第二次循环时直接替换了序列源,可能导致4被提前跳过,最终出现缺失。

修复方案

在每次添加filter时,把当前的prime值快照到一个局部val变量中,让filter捕获这个固定值(而非外部可变变量的引用):

fun sieveCorrect(): Sequence<Int> {
    var sequence = generateSequence(2) { it + 1 }
    return sequence {
        while (true) {
            val prime = sequence.first()
            // 快照当前prime值到局部变量,确保filter捕获固定值
            val currentPrime = prime
            sequence = sequence.filter { it % currentPrime != 0 }
            yield(prime)
        }
    }
}

你的理解误区总结

你错误地假设了两种极端情况:要么所有filter共享同一个prime值,要么每个filter都严格使用创建时的prime值。但实际是:

  • 闭包捕获的是变量引用而非值,序列懒加载延迟了filter的执行时机,导致filter判断时使用的是prime变量的最新值,而非创建filter时的初始值
  • 这种混合状态就造成了既没正确过滤早期质数的倍数(如6、8),又意外跳过或保留了某些数(如4)的异常结果

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.21 19:43:11