如果存在,如何获取Map默认值

时间:2017-03-23 09:56:20

标签: scala scala-collections

我想检索Map的默认值(如果存在)。这是我尝试过的:

def defaultValue[A, B](m: Map[A, B]): Option[B] = {
  m match {
    case m: Map.WithDefault[A, B] => Some(m.default(null))
    case _ => None
  }
}

这不起作用,因为null不是A的子类型。如何检索具有常量函数的Map.WithDefault的默认值?

我尝试了什么

生成A类型的随机值?默认值使用常量函数进行编码,这就是它需要参数的原因,但在我的情况下,不应该使用参数。此外,当我放置???类型Nothing之类的东西时,它会在尝试返回常量值之前评估参数,从而抛出异常。

我的问题与this question有关,但它们没有提供直接检索默认值的方法。

4 个答案:

答案 0 :(得分:2)

您可以添加下限,将方法签名重写为:

def defaultValue[A >: Null <: AnyRef, B](m: Map[A, B]): Option[B]

或者您也可以使用nullA投放到null.asInstanceOf[A]

case m: Map.WithDefault[A, B] => Some(m.default(null.asInstanceOf[A]))

并非此版本也适用于A <: AnyVal(请记住,例如null.asInstanceOf[Int] == 0)。

只需补充一点:您可以与case _: Map.WithDefault[_, _]匹配,因为在运行时无法检查此类型测试中的外部引用。

答案 1 :(得分:0)

我认为你可以通过在任何键上调用#default来实现:

val map = Map(1 -> "a").withDefaultValue("b")

map(1)         // yields "a"
map.default(1) // yields "b"

虽然不是那么好但如果它没有默认值会抛出异常,所以你需要将它包装在Try中,然后使用模式匹配来提取它。

Try(map.default(1)).toOption match {
  case Some(value) => // do something with the value
  case _           => // do something else
}

答案 2 :(得分:0)

您可以使用类型类模式来处理您的问题。您收到错误因为A可以是AnyVal类,如Int,Float等。但您可以简单地克服此限制,请考虑以下事项:

trait DummyProvider[T] {
  def dummy: T
}

implicit def anyRefDummy[T >: Null] = new DummyProvider[T] {
  def dummy: T = null
}

implicit def numericDummy[T](implicit ev: Numeric[T]) = new DummyProvider[T] {
  def dummy: T = ev.zero
}
//probably needs to add instance for boolean

现在您需要在代码中执行以下操作:

def defaultValue[A, B](m: Map[A, B])(implicit ev: DummyProvider[A]): Option[B] = {
  m match {
    case m: Map.WithDefault[A, B] => Some(m.default(ev.dummy))
    case _ => None
  }
}

答案 3 :(得分:0)

这是不可能的

通常这是不可能的,因为默认的“值”实际上是一个函数。因此,一般情况下没有单一的默认值。

以下来源来自Scala 2.12。*。

scala.collection.immutable.Map中存在以下内容:

  /** The same map with a given default function.
   *  Note: `get`, `contains`, `iterator`, `keys`, etc are not affected by `withDefault`.
   *
   *  Invoking transformer methods (e.g. `map`) will not preserve the default value.
   *
   *  @param d     the function mapping keys to values, used for non-present keys
   *  @return      a wrapper of the map with a default value
   */
def withDefault[V1 >: V](d: K => V1): immutable.Map[K, V1] = new Map.WithDefault[K, V1](this, d)

这是来自scala.collection.Map

  /** An abstract shell used by { mutable, immutable }.Map but not by collection.Map
   *  because of variance issues.
   */
  abstract class WithDefault[K, +V](underlying: Map[K, V], d: K => V) extends AbstractMap[K, V] with Map[K, V] with Serializable {
    override def size               = underlying.size
    def get(key: K)                 = underlying.get(key) // removed in 2.9: orElse Some(default(key))
    def iterator                    = underlying.iterator
    override def default(key: K): V = d(key)
}