web-dev-qa-db-ja.com

Scala理解のためのフィルタを備えた未来

以下の例では、例外_Java.util.NoSuchElementException: Future.filter predicate is not satisfied_が発生します

チェックFuture( Test2 )が失敗したときに結果if( i == 2 )が欲しい。フィルターを処理する方法/ if内でifを構成するフューチャーを処理する方法は?

以下は、Scala REPLで機能する簡単な例です。

コード:

_import scala.concurrent.Future
import scala.util.{ Try, Success, Failure }
import scala.concurrent.ExecutionContext.Implicits.global

val f1 = Future( 1 )
val f2 = for {
  i <- f1
  if( i == 2 )
} yield "Test1"
f2.recover{ case _ => "Test2" }
f2.value
_
23
Magnus

_for-comprehension_では、_i == 2_でフィルタリングしています。 _f1_の値は2ではないため、SuccessではなくFailureが生成されます。エラーメッセージが示すように、フィルターの述語は満たされていません。ただし、_f2.recover_は新しいFutureを返します。 _f2_の値は操作されません。 Failureはまだ保存されています。そのため、_f2.value_を呼び出すとエラーメッセージが表示されます。

ここ に示すように、_for-comprehension_でelseを使用することが、私が考えられる唯一の代替案です。

_val f2 = for ( i <- f1) yield {
  if (i == 2) "Test1"
  else "Test2"
}
f2.value
_

これは、_f3.value_と同じようにSome(Success(Test2))を返します。

12
tgr

私の意見では、これはより慣用的な解決策です。この述語関数は、_Future[Unit]_または例外を含む失敗したfutureを作成します。あなたの例では、これはSuccess("Test1")またはFailure(Exception("Test2"))になります。これは「Test1」や「Test2」とは少し異なりますが、この構文の方が便利です。

_def predicate(condition: Boolean)(fail: Exception): Future[Unit] = 
    if (condition) Future( () ) else Future.failed(fail)
_

次のように使用します。

_val f2 = for {
  i <- f1
  _ <- predicate( i == 2 )(new Exception("Test2"))
  j <- f3  // f3 will only run if the predicate is true
} yield "Test1"
_
31
pkinsky

もちろん、自分で1つの解決策を見つけました。おそらく、より優れた、より慣用的なソリューションがありますか?

import scala.concurrent.Future
import scala.util.{ Try, Success, Failure }
import scala.concurrent.ExecutionContext.Implicits.global

val f1 = Future( 1 )
val f2 = for {
  i <- f1
  if( i == 2 )
} yield "Test1"
val f3 = f2.recover{ case _ => "Test2"  }
// OR val f3 = f2.fallbackTo( Future( "Test2" ) )
f3.value
9
Magnus

@pkinskyのアイデアが気に入り、少し改善しました。次のようなExceptionオブジェクトを作成するコードをドロップしました:

val f2 = for {
  i <- f1
  _ <- shouldTrue( i == 2 )
  j <- f3  // f3 will only run if the predicate is true
} yield "Test1"

shouldTrue関数は、lihaoyiの sourcecode ライブラリを使用して実装されます。

def shouldTrue(condition: sourcecode.Text[Boolean])(implicit enclosing: sourcecode.Enclosing, file: sourcecode.File, line: sourcecode.Line): Future[Unit] =
  if (condition.value) Future.successful( () ) else Future.failed(new Exception(s"${condition.source} returns false\n\tat ${file.value}:${line.value}"))

次に、より意味のある例外メッセージを自動的に生成します。

Java.lang.Exception: i == 2 returns false
    at \path\to\example.scala:17
0
pocorall