如何判断 Map 是不是有默认值?

Posted

技术标签:

【中文标题】如何判断 Map 是不是有默认值?【英文标题】:How to tell if a Map has a default value?如何判断 Map 是否有默认值? 【发布时间】:2014-09-02 08:18:03 【问题描述】:

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

如果myMap 有默认值,则返回该值 否则返回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])。

有没有不涉及捕获异常的方法?

【问题讨论】:

【参考方案1】:

可以检查地图是否为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

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

【讨论】:

哦,Map.WithDefault 正是我要找的。谢谢! 请注意,这仍然有点棘手——地图不是静态类型为WithDefault,所以我们必须使用反射。这种反射不会造成显着的性能损失,但仍远非理想。【参考方案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

【讨论】:

它看起来确实更好看!虽然我希望有一种方法可以让我不必在可能引发异常的情况下调用apply(如果可能的话) 如果我错了,有人可能会纠正我,但看起来不可能。引发异常的是Mapdefault 方法。如果只是它返回一个Option,而不是。无论哪种方式,您仍然需要进行某种检查。

以上是关于如何判断 Map 是不是有默认值?的主要内容,如果未能解决你的问题,请参考以下文章

在 Dart 中定义函数时,如何将参数的默认值设置为 ,即空 Map?

Groovy - 如何在不更新地图的情况下使用默认值获取地图值

postgresql 判断字段是不是为空 空给默认值 否则取该字段是啥函数来着?

java中数组变量名的默认值 如定义int[] a;此时a的默认值应该为null吧,如

vuejs的template怎么判断option的值是不是为null或者空数组

内置类型的 std::map 默认值