【问题标题】:Future that cannot fail in Scala在 Scala 中不能失败的未来
【发布时间】:2016-03-19 03:29:16
【问题描述】:

在 Scala 中是否存在不能失败的 Future 的概念?

我正在将可能失败的Future[Result](因此我同时处理FailureSuccess)转换为Future[Option[String]],并带有从失败或成功状态派生的可选错误消息。到目前为止,一切顺利。

事情是现在,我想正式(即,在类型系统的帮助下)记住这个未来将始终持有Success,并且我将来不需要处理失败案例。

有没有聪明的方法来做到这一点?

【问题讨论】:

  • 为什么需要这个?编辑:您是否只是忽略了一些:结果以返回可选的错误消息:字符串?
  • 为什么不Future[Try[T]]
  • @Jean-PhilippePellet 我只是在谈论扩展一个类/特征和覆盖方法并给出错误,但事实证明这是不可能的,或者至少对于Future 来说是不可能的,所有Future impl .是私有的,扩展和覆盖它们似乎是不可能的
  • 我在玩@Jean-PhilippePelle 提出的想法,我使用委托扩展了Future。 scalafiddle.net/console/3ce0331cbd983f1689e1eea65561cac。我工作,但当然,每次您进行转型时,您都会恢复正常的未来。
  • @KevinMeredith Futures don't catch and failed Futures不能容纳致命错误,所以recover { case _ => ??? }相当于recover { case NonFatal(_) => ??? }:docs.scala-lang.org/overviews/core/futures.html#exceptions

标签: scala future


【解决方案1】:

“在类型系统的帮助下”你不能这样做,因为类型系统无法保证 Future 不会失败,即使你保证它不会失败。

考虑一下:

 Future { doStuff(); }
   .recover { case _ => "Failed!" } // Now it always succeeds
   .map { _ => Seq.empty[String].head }  // Now it does not. 

即使您打算进行任何进一步的转换,一旦Future 被声明为始终成功,这仍然无济于事,因为异常处理程序(或您将原始未来转换为“总是成功的") 可以抛出。

更新:正如下面评论中指出的那样,上面的代码 sn-p 是不正确的:.map 的结果与.recover 的结果不同Future。然而,这一点是成立的。这是正确的插图:

Future { doStuff }
  .recover { case _ => Seq.empty[String].head }

【讨论】:

  • .recover { case _ => "Failed!" } 不是一个坏主意,因为你也赶上了java.lang.Error
  • @KevinMeredith 是的......这只是为了说明的一个例子。不要将其投入生产:)
  • recover的结果和map的结果是两个不同的future,所以“it”改变了所指。向编译器断言“我知道一些你不知道的关于恢复结果的事情”本质上并没有错。也许一个副作用检查器是离线运行的。此外,您只需对Nonfatal 异常进行推理。如果它抛出 InterruptedException,那么未来根本就不会完成。所以“成功”是以完成为前提的。
  • 我完全不同意这个答案。您可以为每种失败的类型创建一个表达式 (Sys.error(…))。类型系统首先不会从List().head 中保护您,无论您是将其包装成Future 还是Stream,一旦强制使用Stream,它也会崩溃。但我们仍然使用类型,因为它们很有用。
  • Moreover you only have to reason about Nonfatal exceptions. 那么@som-snytt,您认为只包含{ case scala.util.control.NonFatal(_) => ... 是否合适?
【解决方案2】:

这不就是类型标记的用途吗?

scala> type Tagged[U] = { type Tag = U }
defined type alias Tagged

scala> type @@[T, U] = T with Tagged[U]
defined type alias $at$at

scala> trait OK ; trait Uncertain
defined trait OK
defined trait Uncertain

scala> type Sure[A] = Future[A] @@ OK
defined type alias Sure

scala> type Unsure[A] = Future[A] @@ Uncertain
defined type alias Unsure

scala> val f = Future.successful(42).asInstanceOf[Sure[Int]]
f: Sure[Int] = Future(Success(42))

然后

scala> object X { def p(f: Sure[_]) = "sure" ; def p(f: Unsure[_])(implicit d: DummyImplicit) = "unsure" }
defined object X

scala> X.p(f)
res1: String = sure

当然,在地图下并不确定。

【讨论】:

  • 确实不错。 (a) 我可以为这种Sure[A] 类型添加新方法吗? (b) 我可以让编译器以某种方式告诉我“不要在 Sure[A] 上调用 onFailure,哑”吗?
  • 你可以像往常一样通过类型类做扩展方法。您可以通过引入模棱两可的隐式来为不适用于Sure 的自定义onFailing 创建一个类型类。你正常的 onFailing 只会转发到 f.onFailure。
  • 谢谢。我想你的意思是“你可以通过 implicit 类来做扩展方法。”
  • “类型类”是通用术语,它被实现为“隐式类”。
猜你喜欢
  • 2015-03-12
  • 2020-03-24
  • 2014-06-22
  • 2015-10-28
  • 2017-06-24
  • 2015-09-19
  • 1970-01-01
  • 2014-12-15
  • 1970-01-01
相关资源
最近更新 更多