Scala 基于成功的结果而使未来失败

Scala 基于成功的结果而使未来失败,scala,future,Scala,Future,我的代码中有一个场景,我需要根据包含特定值的成功结果,使未来的失败。通过flatMap,我可以很好地完成这项工作,但我想知道是否有更干净的方法来完成这项工作。首先,一个非常简单的例子: import concurrent._ case class Result(successful:Boolean) object FutureTest { def main(args: Array[String]) { import ExecutionContext.Implicits._

我的代码中有一个场景,我需要根据包含特定值的成功结果,使未来的
失败。通过
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())
    }
  }
}
因此,在这里的示例中,如果返回的
结果
的成功指示器值为
false
,我希望
未来
失败。正如我所提到的,我可以使用
flatMap
使其正常工作,但我想消除的代码行是:

case _ => Promise.successful(result).future
这种说法似乎没有必要。我想要的行为是能够定义条件,如果它的计算结果为真,允许我返回一个不同的
Future
,就像我正在做的那样,但如果它不是真的,就让事情保持原样(有点像
PartialFunction
语义。有没有一种方法可以做到这一点,我只是没有看到?我已经看过
collect
transform
了,但它们似乎也不太合适

编辑

从@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

您可以使用
map
轻松完成这项工作:

val f = Future{ Result(false) } map {
  case Result(false) => throw new Exception("The call failed!!")
  case x => x
}
但是你仍然需要明确地提到你正在传递身份


请注意,在这种情况下使用
是用于副作用,而不是用于更改结果(与同名的
函数1
方法不同)。

还有一种不同的解决方案(没有@cmbaxter提到的stacktrace副作用)

val prom=Promise[Int]()
val f=未来{
1.
}
未完成{
案例成功(i)如果i<5=>prom.failure(新的运行时异常(“<5”))
案例成功率(x)=>毕业舞会成功率(x)
}
未来即将完成{
案例成功=>println(s“We cool'$s'”)
案例失败(th)=>println(s“全部失败,${th.getMessage}”)
}

最干净的解决方案是调用
过滤器
方法,如注释中提到的@senia

Future { Result(false) }.filter(_.successful) // throws NoSuchElementException
如果需要不同的异常类型,可以使用
recoverWith
链接调用:

Future { Result(false) }.filter(_.successful).recoverWith {
  case _: NoSuchElementException => Future.failed(new Exception("The call failed!!"))
}

在这两种情况下,你都想要新的未来?还是只有在失败的情况下?在我的实际代码中,结果本身是从对参与者的调用中返回的。我不希望参与者总是在给定这种结果的情况下向上游传播失败。它是基于通过调用添加密钥成功地将值存储到couchbase中。没有所有调用代码都关心这一点成功标志的值为false;这是情境性的。听起来像是一种方法。@om nom nom,我只希望在满足匹配条件的情况下有一个新的未来。如果不满足匹配条件,就不要管现有的未来。@senia,我查看了
过滤器
。问题是,如果我的谓词不为true,则生成的
未来
将失败一个
NoTouchElementException
,这是不需要的。你应该使用
map
,而不是
,然后再使用
。如果它没有一路抛出异常,然后没有进入我的
onFailure
回调,那么这就行了。当我运行这个时,我在代码执行中得到了堆栈跟踪,所以这不是期望的效果。我很困惑d关于
map
将如何工作。
map
函数将从类型
a
的成功结果变成类型
B
的成功结果。我希望在给定特定条件下,未来失败,这就是我一直使用
flatMap
的原因。@cmbaxter:在这种情况下,
B
A
是同一类型。抛出的结果是,
没有任何东西
是所有类型的子类型,所以它也是
A
@cmbaxter的子类型:这里只有一个答案。wiki资源也是,而不是MMORPG。
Future { Result(false) }.filter(_.successful).recoverWith {
  case _: NoSuchElementException => Future.failed(new Exception("The call failed!!"))
}