【问题标题】:Scala Future return TypeScala 未来返回类型
【发布时间】:2021-02-11 13:03:47
【问题描述】:

我有以下几行代码...

val a = Future { Thread.sleep(10*1000); 42 }
val b = a.map(_ * 2)

当我检查 b 的值后,我打印了以下内容。

scala.concurrent.Future[Int] = Future(Success(84))

如上,b的类型是Future[Int];但在文档中,它说 Future 的 apply 方法总是返回 Future(Try[T])。文档和上面的例子相矛盾。有人可以帮忙吗?

【问题讨论】:

  • 您可以添加文档链接吗?在 std lib 中,我看到 apply 定义:def apply[T](body: =>T)(implicit @deprecatedName('execctx) executor: ExecutionContext): Future[T] 它取决于您的类型。
  • A Future 类似于 Try 但异步。 Future[Try] 通常没有意义,因为 Future 本身可能包含失败或成功的值。

标签: scala future


【解决方案1】:

请发布您的导入和您引用的文档。

我认为与理解这一点最好的平行是:

Try[T] 就像Option[T]Try[T] 总是Success[T](value: T)Failure[T](exception: Throwable),就像Option[T] 总是Some[T](value: T)None

在这样的事情上使用 Scala REPL 也很有帮助。它使您可以轻松查看类型。

我假设你已经这样做了:

scala> import scala.concurrent.Future
import scala.concurrent.Future

scala> import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.ExecutionContext.Implicits.global

scala> import scala.util.{Failure, Success}
import scala.util.{Failure, Success}

现在你有两条线了:

scala> val a = Future { Thread.sleep(10*1000); 42 }
val a: scala.concurrent.Future[Int] = Future(<not completed>)

scala> val b = a.map(_ * 2)
val b: scala.concurrent.Future[Int] = Future(<not completed>)

您可以看到b 的类型仍然是scala.concurrent.Future[Int],因为它使用函数(_: Int -&gt; _ * 2):Int 映射了a 的结果Int,恰好是42

最终:

scala> b
val res0: scala.concurrent.Future[Int] = Future(Success(84))

来自this documentation of Scala Futures

请注意,您期望的 84 被包裹在 Success 中,而后者又被包裹在 Future 中。这是要知道的关键点:Future 中的值始终是Try 类型之一的实例:SuccessFailure。因此,在处理 future 的结果时,请使用常用的Try-handling 技术,或其他 Future 回调方法之一。

最后,从未来中提取Try,要么是Success要么是Failure,我们将从中得到我们的结果,或者一个错误:

scala> b.onComplete {
     |     case Success(value) => println(s"Got the callback, value = $value")
     |     case Failure(e) => e.printStackTrace
     | }
Got the callback, value = 84

【讨论】:

  • 嗨@Randomness Slayer,是的,你是对的。我觉得,我对字符串表示感到非常困惑。感谢您对此进行调查!
  • @user3103957 您的问题有很多答案,您能否将您认为最能充分解决您的问题的答案标记为已接受的答案,这可能有助于其他人在未来寻找答案!
【解决方案2】:

你在这里混合了两件事。创建Future 时,它是使用companion object of Future 中的apply 函数创建的:

def apply[T](body: =>T)(implicit @deprecatedName('execctx) executor: ExecutionContext): Future[T] =
    unit.map(_ => body)

所以只要future没有完成,它的类型就是Future[Int]。未来完成后,结果类型将为Future[Try[Int]]

onComplete 文档所述:

当这个未来通过异常或值完成时,应用提供的函数。

因此,当您打印完成的未来时,它已经成功了。如果您将用更长的等待时间和未完成的未来进行相同的实验,您会发现它的类型尚未成功。

例如下面的代码:

implicit val ec = scala.concurrent.ExecutionContext.global
val a = Future { Thread.sleep(10*1000); 42 }
println(a)
Await.result(a, Integer.MAX_VALUE.seconds)
println(a)

将输出:

Future(<not completed>)
Future(Success(42))

您可以看到该示例正在运行 here

现在让我们看看onComplete。以下代码:

val a = Future { Thread.sleep(10*1000); 42 }
a.onComplete {
  case Success(value) =>
    println(value)
  case Failure(exception) =>
    println(exception)
}

val b = Future { throw new RuntimeException }
b.onComplete {
  case Success(value) =>
    println(value)
  case Failure(exception) =>
    println(exception)
}

Await.result(a, Integer.MAX_VALUE.seconds)
Await.result(b, Integer.MAX_VALUE.seconds)

这里我们可以看到一个示例,当a 应该成功完成并且b 应该抛出时,如何使用onComplete,这正是我们得到的。输出是:

java.lang.RuntimeException
42

因为throwingFuture先完成,所以先打印出来。

【讨论】:

【解决方案3】:

文档说Future[B] 包含Try[B],这是正确的。我认为您对这里的toString 表示感到困惑:Future(Success(84))Future[Int] 的文本表示。对于Future[Try[Int]],您将使用Future(Success(Success(84))) 作为文本表示。

【讨论】:

  • 我认为这里的一个简单的并行示例是Try[T] 就像Option[T]Try[T] 总是Success[T](value: T)Failure[T](exception: Throwable),就像Option[T] 总是Some[T](value: T)None.
猜你喜欢
  • 2016-06-29
  • 1970-01-01
  • 1970-01-01
  • 2020-04-04
  • 1970-01-01
  • 2012-11-28
  • 1970-01-01
  • 2017-04-07
  • 2017-02-18
相关资源
最近更新 更多