当您在单个for循环中使用多个生成器时,您正在展开结果类型。也就是说,您不会得到一个List[List[T]]
,而是得到一个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))
现在,你要如何转化一个
Future[List[T]]
?它不能是一个
Future[T]
,因为你将会得到多个
T
,而一个
Future
(与
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
回顾起来,这个限制应该是相当明显的。问题在于,几乎所有的例子都使用集合,而所有的集合只是 GenTraversableOnce ,因此它们可以自由地混合在一起。此外,Scala被批评的 CanBuildFrom 机制使得可以混入任意集合并返回特定类型,而不是 GenTraversableOnce。
更让事情变得模糊的是,Option 可以转换为 Iterable,这使得可以将选项与集合组合在一起,只要选项不是第一个。
但是,在我看来,造成困惑的主要原因是,在教学推导时从来没有提到这个限制。