さて、理解のために単一のジェネレーターに複数のジェネレーターがある場合、結果の型をフラット化しています。つまり、 を取得する代わりに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
) はそのうちの 1 つしか格納できないため、 にすることはできません。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)
^
これを回避する最も簡単な方法は、複数の内包表記を単純にネストすることです。
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
であるため、自由に混合できることです。それに加えて、CanBuildFrom
Scala が非常に批判されているメカニズムにより、任意のコレクションを混在させて特定の型を取得することが可能になりますGenTraversableOnce
。
そして、物事をさらにぼやけさせるために、Option
を に変換することができますIterable
。これにより、オプションが最初に来ない限り、オプションをコレクションと組み合わせることができます。
しかし、私の意見では、混乱の主な原因は、理解を教えるときに誰もこの制限について言及していないことです.