Предположим, у нас есть неявный поиск параметров, относящийся только к локальным областям действия:
trait CanFoo[A] {
def foos(x: A): String
}
object Def {
implicit object ImportIntFoo extends CanFoo[Int] {
def foos(x: Int) = "ImportIntFoo:" + x.toString
}
}
object Main {
def test(): String = {
implicit object LocalIntFoo extends CanFoo[Int] {
def foos(x: Int) = "LocalIntFoo:" + x.toString
}
import Def._
foo(1)
}
def foo[A:CanFoo](x: A): String = implicitly[CanFoo[A]].foos(x)
}
В приведенном выше коде LocalIntFoo
побеждает ImportedIntFoo
.
Может ли кто-нибудь объяснить, как это считается более конкретным с использованием «правил разрешения статической перегрузки (§6.26.3)»?
Редактировать :
Приоритет привязки имени является убедительным аргументом, но есть несколько нерешенных вопросов. Во-первых, в справочнике по языку Scala говорится:
Если есть несколько подходящих аргументов, которые соответствуют типу неявного параметра, будет выбран наиболее конкретный из них с использованием правил разрешения статической перегрузки (§6.26.3).
Во-вторых, приоритет привязки имени связан с преобразованием известного идентификатора x
в конкретный член pkg.ABx
в случае наличия нескольких переменных / методов / объектов с именем x
в области применения. ImportIntFoo
и LocalIntFoo
имеют разные имена.
В-третьих, я могу показать, что приоритет привязки имен сам по себе не используется следующим образом:
trait CanFoo[A] {
def foos(x: A): String
}
object Def {
implicit object ImportIntFoo extends CanFoo[Int] {
def foos(x: Int) = "ImportIntFoo:" + x.toString
}
}
object Main {
def test(): String = {
implicit object LocalAnyFoo extends CanFoo[Any] {
def foos(x: Any) = "LocalAnyFoo:" + x.toString
}
// implicit object LocalIntFoo extends CanFoo[Int] {
// def foos(x: Int) = "LocalIntFoo:" + x.toString
// }
import Def._
foo(1)
}
def foo[A:CanFoo](x: A): String = implicitly[CanFoo[A]].foos(x)
}
println(Main.test)
Поместите это в test.scala
и запустите scala test.scala
, и он распечатывает ImportIntFoo: 1
.
Это связано с тем, что разрешение статической перегрузки (§6.26.3) говорит о том, что побеждает более конкретный тип.
Если мы делаем вид, что все подходящие неявные значения названы одинаково, LocalAnyFoo
должен был замаскировать ImportIntFoo
.
Связанный :
Это отличный обзор неявного разрешения параметров, но в нем цитируется презентация Nescala Джоша вместо спецификации. Его выступление побудило меня заняться этим.
Реализация компилятора