我正在尝试创建一个类型类Default
为给定类型提供默认值。这是我到目前为止所想到的:
trait Default[A] {
def value: A
}
object Default {
def withValue[A](a: A) = new Default[A] {
def value = a
}
def default[A : Default]: A = implicitly[Default[A]].value
implicit val forBoolean = withValue(false)
implicit def forNumeric[A : Numeric] =
withValue(implicitly[Numeric[A]].zero)
implicit val forChar = withValue(' ')
implicit val forString = withValue("")
implicit def forOption[A] = withValue(None : Option[A])
implicit def forAnyRef[A >: Null] = withValue(null : A)
}
case class Person(name: String, age: Int)
case class Point(x: Double, y: Double)
object Point {
implicit val pointDefault = Default withValue Point(0.0, 0.0)
}
object Main {
def main(args: Array[String]): Unit = {
import Default.default
println(default[Int])
println(default[BigDecimal])
println(default[Option[String]])
println(default[String])
println(default[Person])
println(default[Point])
}
}
上述实现的行为符合预期,但以下情况除外BigInt
and BigDecimal
(以及作为实例的其他用户定义类型Numeric
)它给出的地方null
而不是零。我应该怎么做才能forNumeric
优先于forAnyRef
我得到了我期望的行为?
The forAnyRef
选择隐式是因为它是更具体 than forNumeric
根据 Scala 参考文献的 §6.26.3“重载解析”。有一种方法可以通过将其转移到以下特征来降低其优先级:Default
延伸,像这样:
trait LowerPriorityImplicits extends LowestPriorityImplicits {
this: Default.type =>
implicit def forAnyRef[A >: Null] = withValue(null: A)
}
object Default extends LowerPriorityImplicits {
// as before, without forAnyRef
}
但这只是技巧的一部分,因为现在两者forAnyRef
and forNumeric
彼此一样具体,并且您会得到一个不明确的隐式错误。这是为什么?出色地,forAnyRef
获得额外的特异性点,因为它对A
: A >: Null
。那么你可以做什么,添加一个不平凡的约束forNumeric
,就是将其加倍Default
:
implicit def forNumericVal[A <: AnyVal: Numeric] = withValue(implicitly[Numeric[A]].zero)
implicit def forNumericRef[A <: AnyRef: Numeric] = withValue(implicitly[Numeric[A]].zero)
现在,这个额外的约束使得forNumericVal
and forNumericRef
更具体地说forAnyRef
对于类型,其中Numeric
可用。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)