问题描述
遍历
方法从未来
对象在第一次失败时停止。我想要一个宽容/宽容的版本的这种方法,发生错误时,继续其余的序列。
目前我们已将以下方法添加到我们的工具中:
def traverseFilteringErrors [A,B (seq:Seq [A])
(f:A => Future [B]):Future [Seq [B]] = {
val sentinelValue = null.asInstanceOf [B]
val allResults = Future.traverse(seq){x =>
f(x)recover {case _ => sentinelValue}
}
val successfulResults = allResults map {result =>
result.filterNot(_ == sentinelValue)
}
successfulResults
}
有更好的方法吗?
一个真正有用的东西是能够将未来的错误提升为适当的价值。或者换句话说,将 Future [T]
转换为 Future [Try [T]]
值成为 Success [T]
,而故障情况变为 Failure [T]
)。下面是我们如何实现它:
//也可以更简洁b // f.map(Success(_))。recover {case t:Throwable =>失败(t)}
pre>
//注意:你可能还想将它移动到一个富集类
def mapValue [T](f:Future [T]):Future [Try [T]] = {
val prom = Promise [Try [T]]()
f onComplete prom.success
prom.future
}
现在,如果您执行以下操作:
traverse(seq)(f andThen mapValue)
您将获得成功
未来[Seq [Try [A]]]
,其最终值包含每个成功未来的成功
实例, > Failure 每个失败的未来的实例。
如果需要,您可以在此seq上使用collect
删除Failure
实例,成功值。
换句话说,您可以如下重写您的帮助方法:
def traverseFilteringErrors [A,B](seq:Seq [A])(f:A => Future [B]):Future [Seq [B]] = {
Future.traverse seq)(f andThen mapValue)map(_ collect {case Success(x)=> x})
}
The
traverse
method fromFuture
object stops at first failure. I want a tolerant/forgiving version of this method which on occurrence of errors carries on with the rest of the sequence.Currently we have added the following method to our utils:
def traverseFilteringErrors[A, B <: AnyRef] (seq: Seq[A]) (f: A => Future[B]): Future[Seq[B]] = { val sentinelValue = null.asInstanceOf[B] val allResults = Future.traverse(seq) { x => f(x) recover { case _ => sentinelValue } } val successfulResults = allResults map { result => result.filterNot(_ == sentinelValue) } successfulResults }
Is there a better way to do this?
解决方案A genuinely useful thing (generally speaking) would be to be able to promote the error of a future into a proper value. Or in other words, transform a
Future[T]
into aFuture[Try[T]]
(the succesful return value becomes aSuccess[T]
while the failure case becomes aFailure[T]
). Here is how we might implement it:// Can also be done more concisely (but less efficiently) as: // f.map(Success(_)).recover{ case t: Throwable => Failure( t ) } // NOTE: you might also want to move this into an enrichment class def mapValue[T]( f: Future[T] ): Future[Try[T]] = { val prom = Promise[Try[T]]() f onComplete prom.success prom.future }
Now, if you do the following:
Future.traverse(seq)( f andThen mapValue )
You'll obtain a succesful
Future[Seq[Try[A]]]
, whose eventual value contains aSuccess
instance for each successful future, and aFailure
instance for each failed future.If needed, you can then usecollect
on this seq to drop theFailure
instances and keep only the sucessful values.In other words, you can rewrite your helper method as follows:
def traverseFilteringErrors[A, B](seq: Seq[A])(f: A => Future[B]): Future[Seq[B]] = { Future.traverse( seq )( f andThen mapValue ) map ( _ collect{ case Success( x ) => x } ) }
这篇关于如何继续执行未来序列尽管失败?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!