【问题标题】:How to return different results from Futures in Scala without ending up in nested if statements如何从 Scala 中的 Futures 返回不同的结果而不以嵌套的 if 语句结束
【发布时间】:2018-03-01 13:30:25
【问题描述】:

当涉及到在不同条件下从 Future 返回不同结果时,我实际上正在寻找更好的 Scala 构造。

比方说,在 Future 中,我需要在返回成功结果之前进行某些验证。有两种方法可以做到这一点。

我的方式:

Future {
    if(!validation1()) return Future.failed("Validation1 failed!")
    if(!validation2()) return Future.failed("Validation2 failed!")
    if(!validation3()) return Future.failed("Validation3 failed!")

    Future.successful()
}.flatMap(identity)

方式二:

Future {
    if(!validation1())
        Future.failed("Validation1 failed!")
    else {
        if(!validation2())
            Future.failed("Validation2 failed!")
        else {
            if(!validation3())
                Future.failed("Validation3 failed!")
            else {
                Future.successful("Results")                
            }
        }
    }
}.flatMap(identity)

但是Way I有问题,导致异常scala.runtime.NonLocalReturnControl。你可以在这个链接中找到解释:https://tpolecat.github.io/2014/05/09/return.html

这给我们留下了Way II。不过,这种构造的问题在于,随着验证次数的增加,它很快就会变得丑陋。

谁能提出更好的表达方式?

请让我知道这是否适合这个问题,或者这个问题需要以更好的方式表达。

TIA.

【问题讨论】:

  • 这绝对是此类问题的正确位置;)但是,这两种变体(即使它们有效)似乎都会返回类似Future[Future[String]] 的内容。你真的想要那个吗?如果您不想这样,也许您可​​以尝试调整您的示例,直到它们忠实地代表您希望在实际代码中实现的目标。
  • 我不确定我是否理解正确,但如果您验证某个表单,您通常希望返回所有失败验证的信息,而不仅仅是您找到的第一个。
  • 看起来你可能想使用Validated。
  • pure(fx).flatMap(identity) = fx 对于每个fx: Future[X]
  • @AndreyTyukin 我已修复代码以返回 Future[String]。我在外部未来返回 Future.successful 和 Future.failed 的原因是因为失败案例通常也可以返回异常。实际上这就是我在实际代码中所做的。

标签: scala future


【解决方案1】:

考虑将每个验证提取到单独的Future

def val1():Furure[String] = 
  if validation1() Future.failed("Validation1 failed") else Future.successful("Result")

def val2():Furure[String] = 
  if validation2() Future.failed("Validation2 failed") else Future.successful("Result")

def val3():Furure[String] = 
  if validation3() Future.failed("Validation3 failed") else Future.successful("Result")

然后使用flatMap依次链接它们

val1().flatMap(_ => val2()).flatMap(_ => val3())

或带有语法糖

for {
  _      <- val1()
  _      <- val2()
  result <- val3()
} yield result

【讨论】:

    【解决方案2】:

    怎么样:

    def validation1(): (Boolean, String) // Tuple with e.g. (testResult, "Validation1 failed!")
    
    def validation2(): (Boolean, String)
    
    def validation3(): (Boolean, String)
    
    val firstFound = Seq(validation1(), validation2(), validation3()).find(_._1)
    
    if (firstFound.isEmpty) Success("Results") else Failure(firstFound.map{_._2}.get)
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2013-06-13
      • 2021-09-18
      • 1970-01-01
      • 1970-01-01
      • 2014-01-15
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多