我有一个方法load
,调用相对昂贵。为了在加载期间允许某种异常处理,它返回Try
。我现在需要一个loadAll
方法的实现,它基本上为每个给定的密钥委托给load
。这是我的第一种方法,但我不知道这是否是Try
工作的最佳实践。有没有更好的方法来实现以下目标?
def load(key: K): Try[V] // very expensive
def loadAll(keys: Traversable[K]): Try[Map[K, V]] = {
// remove duplicate keys
val ukeys = Set.empty ++ keys
val result: Iterable[Try[(K, V)]] = ukeys map { key =>
load(key) match {
case Success(value) => Success(key, value)
case Failure(exception) => Failure(exception)
}
}
Try(result.map { _.get }.toMap)
}
答案 0 :(得分:4)
您可以使用折叠来迭代键,然后使用折叠来组合Try
个实例:
def toSet(keys: Traversable[K]): Try[Map[K, V]] = {
keys.toSet.foldLeft( Try( Map.empty[K, V] ) ){ case (tryMap, key) =>
for ( m <- tryMap; v <- load( key ) ) yield m.updated( key, v )
}
}
答案 1 :(得分:2)
如果您对scalaz解决方案感兴趣,这是一项常规操作,可通过名为sequence
的Traversable
仿函数获得。 Try
所需的实例位于scalaz-contrib。这是它的样子:
Welcome to Scala version 2.10.1 (OpenJDK 64-Bit Server VM, Java 1.7.0_21).
Type in expressions to have them evaluated.
Type :help for more information.
scala> import scalaz._, Scalaz._, scalaz.contrib.std.utilTry._
import scalaz._
import Scalaz._
import scalaz.contrib.std.utilTry._
scala> import scala.util.Try
import scala.util.Try
scala> val result: Iterable[Try[(Int, String)]] = Iterable.empty
result: Iterable[scala.util.Try[(Int, String)]] = List()
scala> result.toList.sequence.map(_.toMap)
res0: scala.util.Try[scala.collection.immutable.Map[Int,String]] = Success(Map())
顺便说一下,有一篇论文"The essence of the Iterator pattern",描述/推导traverse
(和sequence
,因为它是特例)。 Eric Torreborre这里有一篇关于本文的精彩摘要。
答案 2 :(得分:2)
这是一个在香草Scala中的单行(假设你已经在范围内Try
):
def loadAll(keys: Traversable[K]) = Try{ keys.toSet.map((k: K) => (k,load(k).get)).toMap }