2015-10-04 34 views
1

鑑於整數以下List ...斯卡拉-理解:如何恢復並繼續如果將來失敗

val l = List(1, 2, 3) 

...我需要調用2種方法,每個元素返回Future和得到以下結果:

Future(Some(1), Some(2), Some(3)) 

這下面是我的嘗試:

import scala.concurrent.Future 
import scala.concurrent.ExecutionContext.Implicits.global 

def f1(i: Int) = Future(i) 
def f2(i: Int) = Future { if (i % 2 == 0) throw new Exception else i } 

val l = List(1, 2, 3) 

val results = Future.sequence(l.map { i = 
    val f = for { 
    r1 <- f1(i) 
    r2 <- f2(i) // this throws an exception if i is even 
    } yield Some(r1) 

    f.recoverWith { 
    case e => None 
    } 
}) 

如果f2失敗,我想恢復並繼續處理剩餘的元素。上面的代碼不起作用,因爲從不調用recoverWith,即使f2失敗。

如何在f2失敗時恢復,以便最終結果如此?

Future(Some(1), None, Some(3)) 

第二元件應當是None因爲f2失敗當輸入整數爲偶數(即2)。

回答

4

recoverWith的輸出類型爲Future時,它工作正常。

import scala.concurrent.Future 
import scala.concurrent.ExecutionContext.Implicits.global 

def f1(i: Int) = Future(i) 
def f2(i: Int) = Future { if (i % 2 == 0) throw new Exception else i } 

val l = List(1, 2, 3) 

val results = Future.sequence(l.map { i => 
    val f = for { 
    r1 <- f1(i) 
    r2 <- f2(i) // this might throw an exception 
    } yield Some(r1) 

    f.recoverWith { 
    case e => Future { println("Called recover " + i); None } // wrapped in Future 
    } 
}) 
results onComplete println 

結果:

// Called recover 2 
// Success(List(Some(1), None, Some(3))  

// tried with scala version: 2.10.4 
2

recoverWith應該返回的東西Future,使你的榜樣甚至不會編譯。

您可以使用recover代替

import scala.concurrent.Future 
import scala.concurrent.ExecutionContext.Implicits.global 

def f1(i: Int) = Future(i) 
def f2(i: Int) = Future { if (i % 2 == 0) throw new Exception else i } 
val l = List(1, 2, 3) 

val results = Future.sequence(l.map { i => 
    val f = for { 
    r1 <- f1(i) 
    r2 <- f2(i) // this throws an exception if i is even 
    } yield Some(r1) 

    f.recover { case _ => None } 
}) 

而且,你甚至不使用r2您的具體的例子,這樣你就可以做到這

val results = Future.sequence(l.map { i => 
    f1(i).map(Some(_)).recover { case _ => None } 
})