我想检索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有关,但它们没有提供直接检索默认值的方法。
答案 0 :(得分:2)
您可以添加下限,将方法签名重写为:
def defaultValue[A >: Null <: AnyRef, B](m: Map[A, B]): Option[B]
或者您也可以使用null
将A
投放到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)
}