2

我有一个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)
}
4

3 回答 3

4

您可以使用 fold 来迭代键,并使用 for 理解来组合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 )
  }
}
于 2013-04-29T14:37:06.227 回答
2

如果您对 scalaz 解决方案感兴趣,这是一个通用操作,可通过Traversable函子获得,称为sequence. 需要的实例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())

顺便说一句,有一篇论文“迭代器模式的本质”,描述/推导traverse(并且sequence,因为它是特殊情况)。Eric Torreborre在这里对这篇论文进行了很好的总结。

于 2013-04-29T15:00:58.417 回答
2

它是香草 Scala 中的单行代码(假设您已经进入Try范围):

def loadAll(keys: Traversable[K]) = Try{ keys.toSet.map((k: K) => (k,load(k).get)).toMap }
于 2013-04-29T22:29:14.237 回答