好吧,当您在一个单一的理解中拥有多个生成器时,您正在扁平化生成的类型。也就是说List[List[T]]
,你得到的不是 a ,而是 a List[T]
:
scala> val list = List(1, 2, 3)
list: List[Int] = List(1, 2, 3)
scala> for (a <- list) yield for (b <- list) yield (a, b)
res0: List[List[(Int, Int)]] = List(List((1,1), (1,2), (1,3)), List((2,1
), (2,2), (2,3)), List((3,1), (3,2), (3,3)))
scala> for (a <- list; b <- list) yield (a, b)
res1: List[(Int, Int)] = List((1,1), (1,2), (1,3), (2,1), (2,2), (2,3),
(3,1), (3,2), (3,3))
现在,您将如何展平 a Future[List[T]]
?它不能是 a Future[T]
,因为您将获得多个T
,并且 a Future
(与 a 相对List
)只能存储其中一个。顺便说一句,同样的问题发生Option
在:
scala> for (a <- Some(3); b <- list) yield (a, b)
<console>:9: error: type mismatch;
found : List[(Int, Int)]
required: Option[?]
for (a <- Some(3); b <- list) yield (a, b)
^
最简单的方法是简单地嵌套多个 for 理解:
scala> for {
| list <- f
| } yield for {
| e <- list
| } yield (e -> 1)
res3: scala.concurrent.Future[List[(String, Int)]] = scala.concurrent.im
pl.Promise$DefaultPromise@4f498585
回想起来,这个限制应该是非常明显的。问题是几乎所有的例子都使用了集合,而所有的集合都是 just GenTraversableOnce
,所以它们可以自由混合。除此之外,Scala 备受批评的CanBuildFrom
机制使得可以混合任意集合并获取特定类型,而不是GenTraversableOnce
.
而且,为了使事情更加模糊,Option
可以将其转换为Iterable
,这使得可以将选项与集合结合起来,只要选项不是最先出现的。
但在我看来,混淆的主要来源是在教授理解力时没有人提到过这个限制。