为什么在映射操作后将Range转换为Vector?

时间:2012-10-29 22:15:52

标签: scala scala-collections

在Coursera上的Scala课程之后,Martin Odersky展示了一个示例代码:

1 to 5 map ( i => i*i )

他说{​​{1}}转换为Range,因为它们共享相同的界面(Vector),结果无法表示为IndexedSeq (在它的例子中更清楚,因为他生成了一对不能表示为Range)的对。

我不确定理解,因为我认为他之前说过,在for表达式中,第一个生成器将确定将要生成的元素类型,并且似乎并非总是如此,至少Range

而且我不确定为什么输出是Range,因为Vector可能不是唯一可以代表上面计算结果的其他实现。

有人可以帮我理解这部分吗?

3 个答案:

答案 0 :(得分:10)

map秘密地将CanBuildFrom作为隐含参数。它的工作是根据您已经获得的新系列(以及内容的类型)生成新的系列。由于Range不能包含任意内容 - 甚至不包含任意整数 - 因此没有CanBuildFrom生成Range。具有Range的{​​{1}}的最具体的超类型是CanBuildFrom。实际构建的集合是IndexedSeq

答案 1 :(得分:2)

正如我相信马丁还解释的那样,for理解对应于(被翻译成)mapflatMap方法的链式调用(以及foreach如果你不要使用yield)。

它通常导致第一个生成器的类型值的原因是mapflatMap通常返回与其接收器相同的类型(map在{{ 1}}返回List等。)。

现在List的问题是它们不能代表不是常规整数序列的东西。因此,Rangemap as defined for Range的返回类型不能为flatMap。下一个最佳匹配是Range,即索引序列的原型实现。

(如果你看一下我链接到的源代码甚至是Scala文档页面,你会发现返回类型有点复杂,但从概念上讲,这就是原因。 编辑: ...现在雷克斯克尔刚刚放弃了Vector炸弹。

答案 2 :(得分:1)

VectorIndexedSeq的默认实现。 map无法表示为Range,因为Range类包含一系列可由开始,停止和步骤值表示的数字(类似于{{ Python中的1}}。 API文档指定它是range的特殊情况。

我们可以看到IndexSeq将为我们提供一个容器值(1,4,9,16,25)。我们可以得到一个开始和停止,但没有恒定的步长值。