2013-05-22 51 views
3

我在我的代碼中有一個場景,我需要根據包含特定值的成功結果使Future失敗。我可以通過flatMap完成這項工作,但我想知道是否有更簡單的方法來完成這項工作。首先,非常簡單的例子:基於成功的結果失敗未來

import concurrent._ 

case class Result(successful:Boolean) 
object FutureTest { 
    def main(args: Array[String]) { 
    import ExecutionContext.Implicits._ 

    val f = Future{Result(false)}.flatMap{ result => 
     result match{ 
     case Result(false) => Promise.failed(new Exception("The call failed!!")).future 
     case _ => Promise.successful(result).future 
     } 
    } 

    f onFailure{ 
     case x => println(x.getMessage()) 
    } 
    } 
} 

所以這裏我舉的例子,我想如果Future返回Result有其成功指示器的false值失敗。正如我所說,我可以使這項工作好與flatMap,但我想消除的代碼行是:

case _ => Promise.successful(result).future 

這種說法似乎沒有必要。我想要的行爲是能夠定義條件,如果它的計算結果爲真,允許我返回一個與我一樣不同的Future,但如果不是這樣,就把事情保持原樣(有點像PartialFunction語義。有沒有辦法做到這一點,我只是沒有看到?我看collecttransform和那些似乎不成爲合適人選任。

編輯

後從@Rex Kerr和@senia獲得map建議,我創建了一個PimpedFuture,並隱式轉換爲代碼,類似如下:

class PimpedFuture[T](f:Future[T])(implicit ex:ExecutionContext){ 
    def failWhen(pf:PartialFunction[T,Throwable]):Future[T] = { 
    f map{ 
     case x if (pf.isDefinedAt(x)) => throw pf(x) 
     case x => x 
    } 
    } 
} 

隱含

implicit def futToPimpedFut[T](fut:Future[T])(implicit ec:ExecutionContext):PimpedFuture[T] = new PimpedFuture(fut) 

而新的處理代碼:

val f = Future{ Result(false) } failWhen { 
    case Result(false) => new Exception("The call failed!!") 
} 

我認爲這是一個少許清潔劑,同時還利用使用map建議。

+0

你想在這兩種情況下*新*未來?或者只有在失敗的情況下? –

+0

結果本身,在我的實際代碼中,是從調用返回給演員的。鑑於這種結果,我不希望該演員總是向上遊傳播失敗。它基於通過調用添加密鑰成功將值存儲到couchbase中。並不是所有的調用代碼都會關心成功標誌的值是否爲false;這是情景。 – cmbaxter

+0

聽起來像['filter'](https://github.com/scala/scala/blob/v2.10.1/src/library/scala/concurrent/Future.scala#L306)方法。 – senia

回答

4

您可以map以較少的努力做到這一點:

val f = Future{ Result(false) } map { 
    case Result(false) => throw new Exception("The call failed!!") 
    case x => x 
} 

,但你仍然需要明確地提到,你通過通過身份。

請注意,在這種情況下您should not使用andThenandThen是用於副作用,而不是用於改變結果(不同於同名的Function1方法)。

+0

你應該使用'map',而不是'和Then'。 – senia

+0

這將工作,如果它只是沒有拋出異常,並沒有得到我的onFailure'回調。當我運行這個時,我在代碼執行中得到一個堆棧跟蹤,所以這不是預期的效果。 – cmbaxter

+0

@cmbaxter - 我的錯誤,senia的權利。 –

0

還有(如@cmbaxter提到的無堆棧跟蹤副作用)不同的解決方案

val prom = Promise[Int]() 
val f = future { 
    1 
} 

f onComplete { 
    case Success(i) if i < 5 => prom.failure(new RuntimeException("_ < 5")) 
    case Success(x) => prom.success(x) 
} 

prom.future onComplete { 
    case Success(s) => println(s"We cool '$s'") 
    case Failure(th) => println(s"All failed, ${th.getMessage}") 
} 
相關問題