2014-11-03 45 views
1

的理解以剧本框架控制器内部下面的代码:处理选项里面对于期货

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]]
  • function1 and function2 can run in par等位基因,但function3需要两者的结果。

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

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

回答

1

我会用Scalaz OptionT去。也许当你只有一个功能未来[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}") 
    } 
+0

我对这种情况增加了另一个依赖关系有点谨慎,但你可能是对的,斯卡拉兹将会得到更多类似的情况。 – Vidya 2014-11-03 16:27:25

+0

它有很多有用的抽象,可以为您节省大量的时间,并使代码更小,我建议您先从http://eed3si9n.com/learning-scalaz/ – 2014-11-03 16:28:57

+0

所以你的解决方案为我工作后,一些调整。但我不知道为什么哈哈。如果你有时间,你能提供一下'optionT'方法的细节吗?什么使得'someOptionT'方法变得必要? – Vidya 2014-11-04 17:55:42

2

也许使用collect,然后你就可以recoverNoSuchElementException,可呈现没错,将从中的任何一步恢复失败。 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")} 
+0

,我想起来了,使用'collect' ISN”与本例中的'.map(_。get)'不同,因为两者都会导致相同的异常被恢复。 – 2014-11-03 16:19:59

+0

也想到了这种方法,但是为'None'情况生成一个例外以后才能捕获它,这感觉有点严重(非惯用)。这可能是最简单的方法。 – Vidya 2014-11-03 16:26:18