Scala不会失败的未来

Scala不会失败的未来,scala,future,Scala,Future,是否存在在Scala中不能失败的未来概念 我正在将可能失败的未来[结果]转换为未来[选项[String]],并携带从失败或成功状态派生的可选错误消息。到目前为止,一切顺利 现在的情况是,我想正式地(即在类型系统的帮助下)记住,这个未来将始终保持成功,并且我将来不需要处理失败案例 有没有一种聪明的方法可以做到这一点?你不能“借助类型系统”做到这一点,因为类型系统无法保证未来的不会失败,即使你承诺不会失败 考虑这一点: Future { doStuff(); } .recover { cas

是否存在在Scala中不能失败的
未来
概念

我正在将可能失败的
未来[结果]
转换为
未来[选项[String]]
,并携带从失败或成功状态派生的可选错误消息。到目前为止,一切顺利

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

有没有一种聪明的方法可以做到这一点?

你不能“借助类型系统”做到这一点,因为类型系统无法保证未来的
不会失败,即使你承诺不会失败

考虑这一点:

 Future { doStuff(); }
   .recover { case _ => "Failed!" } // Now it always succeeds
   .map { _ => Seq.empty[String].head }  // Now it does not. 
即使您要使任何进一步的转换变得不可能,但一旦
未来
被声明为始终成功,这仍然没有帮助,因为异常处理程序(或您将原始未来转换为“始终成功的未来”所做的任何事)可能会抛出异常

更新:正如下面的评论所指出的,上面的代码片段是不正确的:
.map
的结果与
的结果不同。然而,这一点是站得住脚的。以下是正确的说明:

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

这不是类型标记的用途吗

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))
然后


当然,在地图下还不能确定。

为什么需要这个?编辑:你只是忽略了一些:结果来返回可选的错误消息:String吗?为什么不
Future[Try[T]]
?@Jean-philippellet我刚才说的是扩展一个类/特征和重写方法并给出错误,但事实证明这是不可能的,或者至少很容易使用
Future
,所有
Future
impl。是私有的,扩展和覆盖它们似乎是不可能的。我对@Jean Philippelle提出的想法玩了点把戏,我使用委托扩展了未来。我可以工作,但当然,每次你做一个转换,你都会得到一个正常的未来。@KevinMeredith Futures不会捕获,失败的Futures也不会持有致命错误,所以
recover{case}相当于
recover{case NonFatal()=>?}
:这确实很好。(a) 我可以为这样的
Sure[a]
类型添加新方法吗?(b) 我是否可以让编译器告诉我“不要在
上调用onFailure当然[A]
,dummy”?您可以像往常一样通过类型类执行扩展方法。通过引入一个不明确的隐式表达式,可以为自定义的
onFailing
创建一个类型类,该类不适用于
Sure
。您的正常失败将转发给f.onFailure。谢谢。我想你的意思是“你可以通过隐式类来实现扩展方法。”“类型类”是一个通用术语,它被实现为一个“隐式类”。
.recover{case\u=>“Failed!”}
是一个坏主意,因为你也在捕获
java.lang.Error
?@KevinMeredith是的。。。为了举例说明,这只是一个例子。不要将其投入生产:)恢复的结果和映射的结果是两个不同的未来,因此“it”更改referent。向编译器断言“我知道一些你不知道的关于恢复结果的事情”,这本身并没有什么错。也许副作用检查程序是离线运行的。此外,您只需对非致命的异常进行推理。如果它抛出InterruptedException,那么未来就是不完整的。所以“成功”取决于完成。我完全不同意这个答案。您可以为每种失败的类型创建一个表达式(
Sys.error(…)
)。类型系统不会首先阻止您使用
List().head
,无论您是将其包装到
未来的
流中,还是包装到
流中,一旦强制执行
流,它也会崩溃。但是我们仍然使用类型,因为它们很有用。
此外,您只需要对非致命异常进行推理。
那么您认为@som snytt只包含
{case scala.util.control.non致命()=>…
是合适的吗?
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