kotlin中toList()。take(10)和take(10).toList()之间的区别

时间:2018-02-07 12:37:37

标签: kotlin

我只是尝试新的kotlin语言。我遇到了生成无限列表的序列。我生成了一个序列并尝试打印前10个元素。但是下面的代码没有打印任何内容:

fun main(args: Array<String>) {
    val generatePrimeFrom2 = generateSequence(3){ it + 2 }
    print(generatePrimeFrom2.toList().take(10))
}

但是当我在take(10).toList()语句中更改print时,它运行正常。为什么会这样?

这段代码对我来说很好:

fun main(args: Array<String>) {
    val generatePrimeFrom2 = generateSequence(3){ it + 2 }
    print(generatePrimeFrom2.take(10).toList())
}

4 个答案:

答案 0 :(得分:8)

generateSequence函数生成一个无限的序列,或者当传递给它的lambda返回null时完成。在您的情况下,它是{ it + 2 },它永远不会返回null,所以序列是无限的。

当你在序列上调用.toList()时,它将尝试收集所有序列元素,因此如果序列是无限的,则永远不会停止(除非索引溢出或发生内存不足错误),所以它没有打印任何东西,因为它没有完成。

在第二种情况下,相反,在尝试收集其项目之前,您使用.take(10) 限制序列中的元素数量。然后.toList()电话会收集10个项目并完成。

如果您查看此问答语关于Sequence<T>Iterable<T>之间的差异,可能会更加清晰:(link)

答案 1 :(得分:5)

这是提示 - &gt; generate infinite list。在第一个解决方案中,您首先要创建一个列表(等待无穷大)然后获取前10个元素。

在第二个片段中,从无限列表中,您只获取前10个元素并将其更改为列表

答案 2 :(得分:1)

generatePrimeFrom2.toList()尝试计算/创建无限长列表 generatePrimeFrom2.toList().take(10)然后从无限长列表中获取前10个元素 它不会打印,因为它正在计算无限长度列表。

然而,generatePrimeFrom2.take(10)仅尝试计算前10个元素。 generatePrimeFrom2.take(10).toList()将前10个元素转换为列表。

您知道,generateSequence(3){ it + 2 }没有结束。所以它有无限的长度 Sequence没有实际值,在需要时计算,但List必须有实际值。

答案 3 :(得分:1)

  

我遇到了生成无限列表的序列。

这实际上并不正确。重点是序列不是列表。它是一个延迟评估的构造,只有您请求的项目才会实际变为“物化”,即它们在堆上分配的内存。

这就是为什么写

不可互换的原因
infiniteSeq.toList().take(10)

infiniteSeq.take(10).toList()

前者将尝试实例化无限多个项目 - 并且可以预见,会失败。