2013-05-22 22 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}") 
} 
相关问题