1

これは文体に関する質問と、Scala の理解を深めるための私の試みの組み合わせです。

Future を含むリストを取得しました。Future の値を計算し、Option に変換し、for 内包表記を使用してリストを平坦化します。

import scala.util.Try
import scala.concurrent._
import ExecutionContext.Implicits.global

val l= List(Future.successful(1),Future.failed(new IllegalArgumentException))

implicit def try2Traversible[A](xo: Try[A]): Iterable[A] = xo.toOption.toList

val res = for{f <- l; v <- f.value} yield v

scala> res: List[scala.util.Try[Int]] = List(Success(1), Failure(java.lang.IllegalArgumentException))

res.flatten
res16: List[Int] = List(1)

私がやりたいのは、フラット化されたステージを理解することです。誰か提案はありますか?

4

3 に答える 3

2

これを行うのは正しくありません:

for{f <- l; v <- f.value} yield v

先物がすでに満たされているため、valueメンバーが定義されているため、あなたの場合にのみ機能するようです。ただし、一般的なケースでは、for 内包表記を実行したときにまだ満たされていない可能性があり、したがってvalue返さNone れます (ある時点で最終的に満たされるという事実にもかかわらず)。例として、これを REPL で試してください:

val f1 = Future{ 
  Thread.sleep(3000) // Just a test to illustrate, never do this!
  1
}
val f2 = Future{ 
  Thread.sleep(3000) // Just a test to illustrate, never do this!
  throw new IllegalArgumentException
}

val l = List( f1, f2 )
for{f <- l; v <- f.value} yield v

の先物lはまだ満たされていないため、結果は空のリストになります。次に、少し待ってから (最大で 3 秒)、for 内包表記 (最後の行) を再実行すると、先物が最終的に満たされるため、空でないリストが得られます。

これを修正するには、 を使用してブロックする (つまり、すべての先物が満たされるのを待つ)か、またはscala.concurrent.Awaitなどを使用して非同期の世界にとどまる必要があります。たとえば、ブロックしたい場合は、次のようにします。Future.mapFuture.flatMap

Await.result( Future.sequence( l ), duration.Duration.Inf )

Await.result未来の結果を待ち、非同期の世界から同期の世界に移行できるようにします。上記の結果は次のとおりです。ここでList[Int] の問題は、失敗のケースが失われ (結果がList[Try[Int]]望んだものではない)、最初の例外が実際に再スローされることです。これを修正するには、別の回答に投稿したこのヘルパー メソッドを使用できます: https://stackoverflow.com/a/15776974/1632462 それを使用すると、次のことができます。

Await.result( Future.sequence( l map mapValue ), duration.Duration.Inf )

これは、すべての先物が(正しい値またはエラーで)満たされるまで待機し、期待される値を返しますList[Try[Int]]

于 2013-04-15T13:09:31.640 に答える
1

アイデアは、オブジェクトが for-comprehension 自体内のTryオブジェクトOption(つまり、0 または 1 要素のコレクション) であるかのようにトラバースすることです。このトラバーサルが機能するには、Try型から型への変換が必要Optionです。

これはうまくいくはずです:

implicit def try2option[A](xo: Try[A]) = xo.toOption

val res = for (f <- l; t <- f.value; x <- t) yield x
于 2013-04-15T11:40:18.323 に答える
0

Future計算の非同期性を維持するために、最終結果を前後に保持する必要があります。

これを行う(そして を取得するFuture[List[Int]])良い方法は(おそらくあなたが試したものです):

for {
  f <- l    // Extract individual future
  v <- f    // Extract value from future
} yield v

残念ながら、これは次のように変換されます。

l.flatMap(f => f.map(v => v))

Futureは継承しないGenTraversableOnce(そしておそらくすべきではない)ため、これは機能しませんがList、その にはこの特性が必要flatMapです。

ただし、これは手動で行うことができます: val res = l.foldRight(Future.successful(List.empty[Int])) { case (x,xs) => xs.flatMap(vxs => x.map(vx => vx :: vxs)) }


それを行うために使用できますFuture.sequence

Future.sequence(l)

Future[List[Int]]これは、すべての先物が完了したときにのみ完了するを返し、正常に完了した先物のすべての値を含みます。

于 2013-04-16T01:14:26.197 に答える