如何从Scala中的Futures返回不同的结果,而不会在嵌套的if语句中结束

问题描述 投票:4回答:2

我实际上在寻找一个更好的Scala构造,当它在不同条件下返回Future的不同结果时。

可以说,在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)

但是我的方法存在问题,它会导致异常scala.runtime.NonLocalReturnControl。你可以在这个链接中找到解释:https://tpolecat.github.io/2014/05/09/return.html

这让我们留下了Way II。但是这个结构的问题在于它很快会变得丑陋,有更多的验证。

任何人都可以提出更好的表达方式吗?

如果这是这个问题的正确位置,请告诉我,或者需要以更好的方式表达这个问题。

TIA。

scala future
2个回答
4
投票

考虑将每个验证提取到单独的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

0
投票

关于什么:

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)
© www.soinside.com 2019 - 2024. All rights reserved.