代码之家  ›  专栏  ›  技术社区  ›  Walfie

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

  •  4
  • Walfie  · 技术社区  · 10 年前

    是否有方法检查 Map 是否定义了默认值?我想要的是相当于 myMap.getOrElse(x, y) 如果钥匙 x 不在地图中,

    • 如果 myMap 具有默认值,返回该值
    • else返回 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" 因为 我的地图 定义为默认值。但是 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
    

    上述结果得出了预期值,但看起来很混乱。我不会模式匹配和调用 apply 获取或其他 基于映射是否具有默认值,因为类型相同( scala.collection.immutable.Map[String,String] )而不管默认性如何。

    有没有一种方法不需要捕获异常?

    2 回复  |  直到 10 年前
        1
  •  3
  •   Travis Brown    10 年前

    您可以检查映射是否是 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
    

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

        2
  •  2
  •   Michael Zajac    10 年前

    你可以使用 Try 而不是尝试/捕捉,这样看起来会更干净一些。

    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