【问题标题】:.map or match returning Future[List] when expected to return List.map 或 match 在预期返回 List 时返回 Future[List]
【发布时间】:2022-02-01 17:29:33
【问题描述】:

我有点失败了这种奇怪的行为,不确定我到底错在哪里。所以情况是tester2 函数正在返回一个 Future[Boolean]] 现在我想等待它完成,当它完成时我希望它根据reset 函数内部的不同情况返回一个 List[String] ,现在的问题是返回 List[String] 而不是返回 Future[List[String]] ,无法理解为什么匹配函数会这样

确切地说,我得到了这个错误

    val les = Await.ready(tester2(5),Duration.Inf).map(reset).forEach(println)

object HelloWorld {

def main(args: Array[String]) {


    val exp = tester2(5).map(reset)

    val les = Await.ready(tester2(5),Duration.Inf).map(reset).forEach(println)
    println(s"what do you say ${les}")


}
def reset (x: Option[Boolean]): List[String] =
  x match {
    case None =>  List("abc","def")
    case Some(false) =>  List("abc","def")
    case Some(true) =>  List("def","abc")
  }

def tester():Future[Option[Message]]={
    Future{
        Thread.sleep(5000)
        Option(Message("abc","def","ghi"))
    }
}
def tester2(param:Int):Future[Option[Boolean]]={
    Future{
        Thread.sleep(5000)
        if(param>10){
            Some(true)
        }else{
            Some(false)
        }
        
       
    }
}

【问题讨论】:

  • 您没有正确输入错误。那是一行代码,可能是复制粘贴错误?
  • 你永远不会想要Await 和Future,这基本上破坏了首先使用Future 的整个想法。您想将其转换为另一个 Future 并在整个链中一直返回它,直到 main 或其他东西。
  • @LuisMiguelMejíaSuárez 我完全理解你的意思,但这只是对我试图理解的真实代码的模仿
  • @LuisMiguelMejíaSuárez 我认为向他们不能使用Await .result 的人解释没有帮助。全世界每个使用 Future 的 Scala 程序都至少有 1 个 await 语句……否则它永远不会产生任何输出。它对于在孤立的代码片段中掌握和研究期货特别有用。在他们意识到Await.result 的潜在死锁影响并开始专注于删除它的所有实例之后。然而,教授 Await.result 是理解 Futures 的核心,而你会因为忽略它而迷惑人们。 Option.get 也是如此
  • @Philluminati “Await.result 是理解 Futures 的核心” 不,它不是,它只是一个快速的技巧,你可以在简短的例子中使用,或者在你不想要的时候使用实际使用Futures,但您依赖于第三方库。 - “他同样适用于 Option.get” Option.get 不应该真的存在,它没有一个有效的用例。 - “全世界每个使用 Future 的 Scala 程序都至少有 1 个 await 语句” 我怀疑,大多数使用 Future 的 Scala 程序都将使用框架接受Future 作为最终结果,并且会完成这项肮脏的工作。

标签: scala asynchronous async-await future options


【解决方案1】:

如果 tester2 返回一个布尔选项的未来

def tester2(param:Int):Future[Option[Boolean] = ???

并且您想将值更改为字符串,您需要说“当这个未来完成并且有一个真正的 Option[Boolean].. 然后做这件事。这就是“地图”对未来所做的事情。它说“一旦未来完成,运行这段代码”。所以你可以这样做:

def reset (in :Future[Option[Boolean]]) = in.map { optionOfBoolean :Option[Boolean] =>

    optionOfBoolean match {
        case None => ...
        case Some(true) ...
    }
}

Scala 还允许您将map 和match 放在一起,然后编写:

def reset (in :Future[Option[Boolean]]) = in map {
    case None => List("abc", "bcd")
    case Some(true) => List("d3", "d4")
    case Some(false) => List("sds", "dssds")
}

由于我看不到您的错误,我无法进一步帮助您,但这样的事情应该可以工作。

val booleanResult :Future[Option[Boolean]] = tester2(...)
val futureListStr :Future[List[String]] = reset(booleanResult)
val answer :List[String] = Await.result(futureListStr, scala.concurrent.duration.Duration.Inf)

【讨论】:

  • 感谢您首先回答我想了解的@philuminati,在我的reset 中,正如您所看到的,我期望在不同的布尔值上返回具有不同值的List[String],我的问题是即使返回类型是 List[String] ,当我将 reset 函数映射到 Future[Option[Boolean]] 上时,它也应该返回 List[String] 但它不是返回 Future[List[String]] 。我对这部分感到困惑,只是为什么它将我的列表包装在未来中
  • 还有一件事@philuminati,在你的代码中我可以看到你正在使用await和futureListStr,我只是想确认它是否会间接等待tester2完成因为,因为 futureListStr 的值间接取决于它
  • tester2 创造了一个未来。 “将来你会得到这个布尔选项”。 reset 致电 map 谈论未来。它说“当未来完成时调用这个函数”。如果您知道什么是函数回调,那么这应该是有道理的。运行的函数是地图内的代码块{}。它不引用未来,因为代码等到未来运行。这样是安全的。在未来调用 map 表示当我们拥有它时将此函数应用于结果。所以您可以使用函数 A -> B 将 Future[A] 转换为 Future[B](我们在地图中拥有的内容)
  • 但是将Future[X] 转回X 的唯一方法是使用Await.result。这就是我在程序结束时所做的。等待一切发生。我可以重新排列代码,以便 reset 采用 Option[Boolean] 返回 List[String] (基本上是函数映射部分中的内容)然后我可以这样做:val innner = Await.result(tester2, Duration.Inf); val answer = reset(inner) 或者我可以保留映射 val answer = Await.result(tester2(..).map(reset), Duration.Inf)最后特别干净
【解决方案2】:

使用Await.result提取结果值。

final def result[T](awaitable: Awaitable[T], atMost: Duration): T

等待并返回 Awaitable 的结果(类型 T)。

awaitable要等待的Awaitable

atMost 最长等待时间,可以是负数(不进行等待),>Duration.Inf 表示无限等待,或有限的正数持续时间

返回如果 awaitable 在特定的最大等待时间内完成,则返回结果值

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-02-09
    • 2022-07-11
    • 1970-01-01
    • 2019-06-28
    相关资源
    最近更新 更多