处理内部期权理解期权

时间:2014-11-03 16:06:02

标签: scala playframework future optional playframework-2.3

考虑Play Framework控制器中的以下代码:

val firstFuture = function1(id)
val secondFuture = function2(id)
val resultFuture = for {
  first <- firstFuture
  second <- secondFuture(_.get)
  result <- function3(first, second)
} yield Ok(s"Processed $id")
resultFuture.map(result => result).recover { case t => InternalServerError(s"Error organizing files: $t.getMessage")}

以下是有关这些功能的一些细节:

  • function1返回Future[List]
  • function2返回Future[Option[Person]]
  • function1function2可以并行运行,但function3需要两者的结果。

鉴于此信息,我有一些问题:

  • 虽然应用程序是这样的代码不太可能用不正确的id调用,但我想处理这种可能性。基本上,如果NotFound返回function2,我想返回None,但我无法弄清楚如何做到这一点。
  • recover调用是否会处理Exception抛出的任何一步?
  • 是否有更优雅或惯用的方法来编写此代码?

2 个答案:

答案 0 :(得分:2)

也许使用collect,然后你可以recover NoSuchElementException - 是的,将从任何一步恢复失败。 resultFuture将使用映射的Result成功,或者在抛出的第一个异常时失败。

val firstFuture = function1(id)
val secondFuture = function2(id)
val resultFuture = for {
   first <- firstFuture
   second <- secondFuture.collect(case Some(x) => x)
   result <- function3(first, second)
} yield Ok(s"Processed $id")

resultFuture.map(result => result)
   .recover { case java.util.NoSuchElementException => NotFound } 
   .recover { case t => InternalServerError(s"Error organizing files: $t.getMessage")}

答案 1 :(得分:1)

我会选择Scalaz OptionT。也许当你只有一个函数Future [Optipn [T]]它有点矫枉过正,但是当你开始添加更多功能时它会变得非常有用

  import scala.concurrent.ExecutionContext.Implicits.global
  import scalaz.OptionT
  import scalaz.OptionT._
  import scalaz.std.scalaFuture._

  // Wrap 'some' result into OptionT
  private def someOptionT[T](t: Future[T]): OptionT[Future, T] = 
    optionT[Future](t.map(Some.apply))

  val firstFuture = function1(id)
  val secondFuture = function2(id)

  val action = for {
    list <- someOptionT(firstFuture)
    person <- optionT(secondFuture)
    result = function3(list, person)
  } yield result

  action.run.map {
    case None => NotFound
    case Some(result) => Ok(s"Processed $id")
  } recover {
    case NonFatal(err) => InternalServerError(s"Error organizing files: ${err.getMessage}")
  }