隐式参数解析-设置优先级 [英] Implicit parameter resolution - setting the precedence

查看:90
本文介绍了隐式参数解析-设置优先级的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试创建一个类型类Default,该类型类提供给定类型的默认值.到目前为止,这是我想出的:

I am trying to create a typeclass Default that supplies the default value for a given type. Here is what I have come up with so far:

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])
  }
}

除了BigIntBigDecimal的情况(以及其他用户定义的类型为Numeric的实例)的情况以外,上述实现的行为与预期的一样,其中给出的是null而不是零.我应该怎么做才能使forNumeric优先于forAnyRef并且得到我期望的行为?

The above implementation behaves as expected, except for the cases of BigInt and BigDecimal (and other user defined types that are instances of Numeric) where it gives null instead of zero. What should I do so that forNumeric takes precedence over forAnyRef and I get the behavior I expect?

推荐答案

之所以选择forAnyRef隐式,是因为根据§6.26.3重载分辨率",它隐含的是forNumeric更具体 Scala参考.有一种方法可以通过将其移至Default扩展的特征来降低其优先级,如下所示:

The forAnyRef implicit is chosen because it is more specific than forNumeric according to §6.26.3 "Overloading Resolution" of the Scala reference. There is a way to reduce its priority by moving it to a trait that Default extends, like this:

trait LowerPriorityImplicits extends LowestPriorityImplicits {
  this: Default.type =>

  implicit def forAnyRef[A >: Null] = withValue(null: A)

}

object Default extends LowerPriorityImplicits {
  // as before, without forAnyRef
}

但这只是窍门的一部分,因为现在forAnyRefforNumeric都一样具体,并且您将得到一个含糊不清的隐式错误.这是为什么?好吧,forAnyRef获得了一个额外的特异性点,因为它对A:A >: Null有着非平凡的约束.然后,要对forNumeric添加非平凡约束,您可以做的就是在Default中将其加倍:

But that's only part of the trick, because now both forAnyRef and forNumeric are as specific as each other, and you'll get an ambiguous-implicit error. Why is that? Well, forAnyRef gets an extra specificity point because it has a non-trivial constraint on A: A >: Null. What you can do then, to add a nontrivial constraint to forNumeric, is to double it in Default:

implicit def forNumericVal[A <: AnyVal: Numeric] = withValue(implicitly[Numeric[A]].zero)

implicit def forNumericRef[A <: AnyRef: Numeric] = withValue(implicitly[Numeric[A]].zero)

现在,对于可用Numeric的类型,此附加约束使forNumericValforNumericRefforAnyRef更具体.

Now, this additional constraint makes forNumericVal and forNumericRef more specific that forAnyRef for types where a Numeric is available.

这篇关于隐式参数解析-设置优先级的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆