组成必需值和可选值的期货

Posted

技术标签:

【中文标题】组成必需值和可选值的期货【英文标题】:Composing Futures of a required and optional value 【发布时间】:2021-07-26 21:30:02 【问题描述】:

假设我正在编写一个接收Future[A]Future[B] 并返回Future[(A, Option[B])] 的函数,如下所示:

// return the result of "fa" and then
// either "Some" of the result of "fb" if "fb" has been completed successfully
// or None if "fb" is still not completed or failed
// Note: we check `fb` result after `fa` has completed.

def foo(fa: Future[A], fb: Future[B]): Future[(A, Option[B])] = ???

// foo(Future.successful(a), Future.successful(b)) // Future.successful(a, Some(b))
// foo(Future.successful(a), Future.failed(...))   // Future.successful(a, None)
// foo(Future.successful(a), Future.never)         // Future.successful(a, None)
// foo(Future.failed(...),   Future.successful(b)) // Future.failed(...)
// foo(Future.failed(...),   Future.never)         // Future.failed(...)

我这样写foo

def foo(fa: Future[A], fb: Future[B]): Future[(A, Option[B])] = for 
  a <- fa
  ob <- if (fb.isCompleted) fb.recover  case NonFatal(_) => None  else Future.successful(None)
 yield (a, ob)

这个实现似乎有效。您将如何纠正或改进它?

【问题讨论】:

【参考方案1】:

您可以使用value 轻松定义foo

def foo(fa: Future[A], fb: Future[B])(implicit ec: ExecutionContext): Future[(A, Option[B])] =
  fa.map(a => a -> fb.value.flatMap(_.toOption))

这很有效,因为value 正是你想要的,如果它完成了Future 的价值或None;此外,由于该值还捕获了作为 Try 失败的可能性,而您所要做的就是将其转换为 Option,您就有了一个漂亮的单线。

一如既往,Scaladoc 是您的朋友 ;)

【讨论】:

值得注意的是,此解决方案需要在范围内隐式使用 ExecutionContext。我会考虑fa.zip(Future.successful(fb.value.flatMap(_.toOption))) 或者使用ExecutionContext.parasitic 明确传递给fa.map,因为要做的工作很少而且没有影响。 @ViktorKlang 谢谢。 fb.value 是否在 fa 完成后调用?我需要等待fa 完成,然后检查fb 是否完成。我猜map 解决方案是这样工作的。 啊,所以你想要“最早在 fa 完成后”的值?然后 map 会更好,因为 zip 渴望在其参数中。 是的,我想要在完成fa 之后的value。我将更新问题以使其清楚。

以上是关于组成必需值和可选值的期货的主要内容,如果未能解决你的问题,请参考以下文章

用返回非可选值的计算属性覆盖返回可选值的计算属性

如何编写处理可选值的字典扩展

防范具有 nil 可选值的开关按钮

Swift:XCTest 会修改状态吗?可以返回可选值的测试函数的约定是啥?

我们可以为返回可选值的 swift 函数添加 @objc 吗?

Swift 中的可选值是啥?