2014-11-03 48 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