如何判断Map是否具有默认值?

时间:2014-07-11 16:19:24

标签: scala map default-value

有没有办法检查Map是否有定义的默认值?我想要的是等同于myMap.getOrElse(x, y),如果关键x不在地图中,

  • 如果myMap具有默认值,则返回该值
  • else return y

该问题的一个人为举例:

scala> def f(m: Map[String, String]) = m.getOrElse("hello", "world")
f: (m: Map[String,String])String

scala> val myMap = Map("a" -> "A").withDefaultValue("Z")
myMap: scala.collection.immutable.Map[String,String] = Map(a -> A)

scala> f(myMap)
res0: String = world

在这种情况下,我希望res0"Z"而不是"world",因为myMap被定义为默认值。但是getOrElse并没有这样做。


我可以使用m.apply代替m.getOrElse,但不保证地图有默认值,因此可能会抛出异常(我可以捕获异常,但这是非理想的)。

scala> def f(m: Map[String, String]) = try {
     |   m("hello")
     | } catch {
     |   case e: java.util.NoSuchElementException => "world"
     | }
f: (m: Map[String,String])String

scala> val myMap = Map("a" -> "A").withDefaultValue("Z")
myMap: scala.collection.immutable.Map[String,String] = Map(a -> A)

scala> f(myMap)
res0: String = Z

scala> val mapWithNoDefault = Map("a" -> "A")
mapWithNoDefault: scala.collection.immutable.Map[String,String] = Map(a -> A)

scala> f(mapWithNoDefault)
res1: String = world

以上产生了预期值,但似乎很混乱。我无法模式匹配并根据地图是否具有默认值来调用applygetOrElse,因为类型相同(scala.collection.immutable.Map[String,String]),无论默认值如何 - 岬。

有没有办法做到这一点并不涉及捕捉异常?

2 个答案:

答案 0 :(得分:3)

您可以检查地图是否是Map.WithDefault的实例:

implicit class EnrichedMap[K, V](m: Map[K, V]) {
  def getOrDefaultOrElse(k: K, v: => V) =
    if (m.isInstanceOf[Map.WithDefault[K, V]]) m(k) else m.getOrElse(k, v)
}

然后:

scala> val myMap = Map("a" -> "A").withDefaultValue("Z")
myMap: scala.collection.immutable.Map[String,String] = Map(a -> A)

scala> myMap.getOrDefaultOrElse("hello", "world")
res11: String = Z

scala> val myDefaultlessMap = Map("a" -> "A")
myDefaultlessMap: scala.collection.immutable.Map[String,String] = Map(a -> A)

scala> myDefaultlessMap.getOrDefaultOrElse("hello", "world")
res12: String = world

这种反射是否比使用非异常控制流的异常更好是一个悬而未决的问题。

答案 1 :(得分:2)

您可以使用Try代替try / catch,它看起来会更清晰。

val m = Map(1 -> 2, 3 -> 4)

import scala.util.Try 

Try(m(10)).getOrElse(0)

res0: Int = 0

val m = Map(1 -> 2, 3 -> 4).withDefaultValue(100)

Try(m(10)).getOrElse(0)

res1: Int = 100