Scala中隐含的低优先级和高优先级

low priority and high priority implicits in scala

在以下来自 Scala 的 puzzlers 的代码中,隐式似乎没有冲突,因为 TestAlarmHandler 更具体。虽然我不明白解释。为什么 TestAlarmHandlerDefaultAlarmHandler 更具体?

object Scanner {
  trait Console { def display(item: String) }
  trait AlarmHandler extends (() => Unit)
  def scanItem(item: String)(implicit c: Console) {
    c.display(item)
  }
  def hitAlarmButton()(implicit ah: AlarmHandler) { ah() }
}


class OperatingMode {
  implicit val ConsoleRenderer = new Scanner.Console {
    def display(item: String) { println(s"Found a ${item}") }
  }
  implicit val DefaultAlarmHandler = new Scanner.AlarmHandler {
    def apply() { println("ALARM! ALARM!") }
  }
}
object NormalMode extends OperatingMode
object TestMode extends OperatingMode {
  override implicit val ConsoleRenderer = new Scanner.Console {
    def display(item: String) { println("Found a detonator") }
  }
  implicit val TestAlarmHandler = new Scanner.AlarmHandler {
    def apply() { println("Test successful. Well done!") }
  }
}
import NormalMode._
scala> Scanner scanItem "knife"
Found a knife
scala> Scanner.hitAlarmButton()
ALARM! ALARM!
import TestMode._
scala> Scanner scanItem "shoe"
Found a detonator
scala> Scanner.hitAlarmButton()
Test successful. Well done!

那是因为 TestMode 是 OperationMode 的子类,scala 首先在 TestMode 的范围内查找隐式,只有在找不到时才会在层次结构中查找。

TestAlarmHandlerDefaultAlaramHandler 更具体,因为 TestAlarmHandler 是在匿名 class 中定义的,它派生自 class OperatingMode 定义DefaultAlarmHandler.


形式上,the Scala Language Specification 指定了当找到多个符合条件的参数时如何处理的情况,如下所示(请注意,TestAlarmHandlerDefaultAlarmHandler 都符合条件,因为它们已被由 import TestMode._ 导入):

If there are several eligible arguments which match the implicit parameter's type, a most specific one will be chosen using the rules of static overloading resolution.

6.26.3 Overloading Resolution节根据相对权重的概念定义了更具体的概念:

The relative weight of an alternative A over an alternative B is a number from 0 to 2, defined as the sum of

  • 1 if A is as specific as B, 0 otherwise, and
  • 1 if A is defined in a class or object which is derived from the class or object defining B, 0 otherwise.

TestAlarmHandler相对于DefaultAlarmHandler的相对权重为1,而DefaultAlarmHandler相对于TestAlarmHandler的相对权重为0。注意TestAlarmHandler定义在一个匿名 class 派生自 class OperatingMode 定义 DefaultAlarmHandler。第一条规则在解决方法重载时很重要,但在这里不相关。

An alternative A is more specific than an alternative B if the relative weight of A over B is greater than the relative weight of B over A.

TestAlarmHandlerDefaultAlaramHandler 更具体,因为 TestAlarmHandler 相对于 DefaultAlarmHandler 的相对权重大于相反的权重。