8

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

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

他说,因为它们共享相同的接口 ( ),所以将其Range转换为 a ,并且结果无法表示为 a (在其示例中更清楚,因为他生成了一对不可表示为 a )。VectorIndexedSeqRangeRange

我不确定是否理解,因为我认为他之前说过,在 for 表达式中,第一个生成器将确定将产生的元素类型,而且它似乎并不总是正确的,至少对于Range.

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

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

4

3 回答 3

10

map偷偷地将 aCanBuildFrom作为隐含参数。它的工作是根据您已经拥有的集合(以及内容的类型)生成一个新集合。由于Range不能包含任意的东西——甚至是任意的整数——所以没有CanBuildFrom产生Range. 最具体的超类型Range确实有CanBuildFromis IndexedSeq。由 this 实际构建的集合是一个Vector.

于 2012-10-29T22:26:18.420 回答
2

正如我确信 Martin 也解释过的那样,for理解对应于(被翻译成)mapflatMap方法的链式调用(foreach如果你不使用yield)。

它通常导致第一个生成器类型的值的原因是map并且flatMap通常返回与它们的接收器相同的类型(map在 aList返回 aList等)。

现在Ranges 的问题是它们不能表示不是常规整数序列的事物。因此,定义map的and的返回类型不能是。下一个最佳匹配是索引序列的原型实现。flatMap RangeRangeVector

(如果您查看源代码甚至我链接到的 Scala 文档页面,您会发现它比返回类型要复杂一些,但从概念上讲,这就是原因。编辑: ......现在是 Rex可儿刚刚扔了CanBuildFrom炸弹。

于 2012-10-29T22:25:11.173 回答
1

Vector是 的默认实现IndexedSeqmap不能表示为 a ,Range因为Range该类被设计为包含一系列数字,这些数字可以用 start、stop 和 step 值表示(类似于rangePython 中的值)。API 文档指定它是IndexSeq.

我们可以看到1 to 5 map { i => i * i }会给我们一个值容器(1、4、9、16、25)。我们可以获得开始和停止,但没有恒定的步长值。

于 2012-10-29T22:23:12.140 回答