【问题标题】:Getting values from scala futures从 Scala 期货中获取价值
【发布时间】:2020-09-16 17:44:11
【问题描述】:

我是 scala 的新手,正在研究 Futures。所以我有一个返回 Future 的方法调用,我的代码如下。

val futureResult =  data.getState  //this returns future
    Await.result(id, 10 seconds)  //  waiting for future to complete
  futureResult .onComplete({
      case Success(result) => logger.info(s"resultis.. ${result}")
      case Failure(exception) => exception.printStackTrace()
    })

如果成功,我会在“结果”中得到想要的结果。但是我想在变量中获取结果的值,以将其传递给其他方法。我试过了。

val finalResult = futureResult.onComplete({
      case Success(result) => logger.info(s"resultis.. ${result}")
      case Failure(exception) => exception.printStackTrace()
    })

当我打印 finalResult 时,它是空的。我如何才能使结果具有价值,以便它可以在其他地方使用

【问题讨论】:

  • 为什么不能在success里面调用那个函数?

标签: scala


【解决方案1】:

当您开始使用Futures 和类似的对象时,它们统称为“函子”或“单子”,取决于它们的功能,(check out this guide on functors with amazing animated pictures) 您正在使用具有特殊属性的容器、盒子,而您并不除非绝对必要,否则希望从中“获得价值”。在Future 的情况下,容器代表一个异步计算的值。

这意味着您应该使用mapflatMap 和类似的方法来使用计算结果。这样,您可以保持整个计算异步。同样,代码中的其他函数应该返回 Futures 并且应该尽可能多地携带它们。 Here is the Scala docs overview on Future

同时,如果您将 Future 分配给变量,则您将“未来容器”分配给变量,而不是 Future 将包含的值。这就是为什么您不能在第二个示例中打印 finalResult

例如,您可以尝试:

def doSomething(value: String): Unit = ???
def calculateSomething(value: String): Boolean = ???
def calculateSomethingElse(value: Boolean): Future[Int] = ???

def myCode(...): Future[Int] = {
  someCallThatReturnsFutureOfString(...)
    .map { result =>
      logger.info(s"Result is... $result")
      // More computations with result
      doSomething(result)
      calculateSomething(result)
    }
    .flatMap { someCalculationResult =>
      // More computations....
      calculateSomethingElse(result)
    }
  }

如果您想处理异常,正如我想的那样,this other answer 就是您要寻找的,因为transform 允许您操纵成功的结果以及异常。

futureResult transform {
  case Success(result) =>
    println(s"Result is... $result")
    // More computations with result
    Success(calculateSomething(result))

  case f @ Failure(exception) =>
    exception.printStackTrace()
    f
}

我知道,我听起来好像没有回答你的问题。你可能会想“嘿,我想把价值拿出来并在其他地方使用,这家伙不是告诉我的”,但除非特定情况不是它们的本意。转换到这种思维方式需要付出努力,而且一开始很难“看到它应该如何完成”。

如果你还想把价值拿出来,那么文森特的回答是不错的。

【讨论】:

    【解决方案2】:

    最好这样做:

    val futureResult =  data.getState.map(res => fn(res))  //this returns future
      futureResult .onComplete({
          case Success(result) => logger.info(s"resultis.. ${result}")
          case Failure(exception) => exception.printStackTrace()
        })
    

    或者至少:

    val futureResult =  data.getState  //this returns future
      futureResult .onComplete({
          case Success(result) => 
               logger.info(s"resultis.. ${result}")
               fn(result)
          case Failure(exception) => exception.printStackTrace()
        })
    

    但是执行 Await.result 会暴露一个事实,即在 Future 失败的情况下可能会引发异常,并使您的程序崩溃。

    包含您预期的“finalResult”的内容是 Await.result 返回的内容

    查看方法契约:

    def result[T](awaitable : scala.concurrent.Awaitable[T], atMost : scala.concurrent.duration.Duration) : T
    

    【讨论】:

    • 应该撰写而不是“提取”。想要从一元类型(FutureOption、...)中“提取”值会导致代码异味(通常是误解或不良设计的症状)。
    猜你喜欢
    • 2018-03-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-09-01
    • 1970-01-01
    • 1970-01-01
    • 2014-05-29
    • 1970-01-01
    相关资源
    最近更新 更多