Приоритет ограничения типа Scala в неявном разрешении

У меня есть эти 2 следствия

trait A[T] {
  val name: String
}

trait B

object A {
  implicit def product[T <: Product] = new A[T] {
    override val name: String = "product"
  }

  implicit def childOfB[T <: Product with B] = new A[T] {
    override val name: String = "child of B"
  }
}

и если я попытаюсь найти неявный экземпляр A[C] где C является

case class C() extends B

childOfB будет выбран.

Я знаю, что это логично, но почему это происходит? Я не могу найти это нигде документально.

3 ответа

Решение

Спецификация языка Scala гласит:

Если имеется несколько подходящих аргументов, которые соответствуют типу неявного параметра, наиболее определенный из них будет выбран с использованием правил разрешения статической перегрузки.

Разрешение перегрузки имеет представление о том, что один символ более специфичен, чем другой. Точное, общее определение специфичности довольно сложно (как вы можете видеть в приведенной выше спецификации), но в вашем случае оно сводится к тому, что childOfB охватывает строго подмножество типов, охватываемых product и, следовательно, более конкретно.

Спецификация говорит

Если имеется несколько подходящих аргументов, которые соответствуют типу неявного параметра, наиболее определенный из них будет выбран с использованием правил разрешения статической перегрузки.

Чтобы расширить ответ @ghik, из Программирование в Scala,

Чтобы быть более точным, одно неявное преобразование является более конкретным, чем другое, если применяется одно из следующих:

  • Аргумент первого является подтипом последнего
  • Оба преобразования являются методами, и включающий класс первого расширяет охватывающий класс второго

Я предполагаю, что "аргумент" в этой цитате относится также к параметрам типа, как это предлагается

object A {
  implicit def A2Z[T <: A] = new Z[T] {println("A")}
  implicit def B2Z[T <: B] = new Z[T] {println("B")}
}

trait A
trait B extends A

trait Z[T]

def aMethod[T <: A](implicit o: Z[T]) = ()

implicit val a: A = new A {}

aMethod // prints B even though we started with an A
Другие вопросы по тегам