Scala: Неявный приоритет разрешения параметров

Предположим, что мы имеем неявный поиск параметров, относящийся только к локальным областям:

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 Language Reference говорит:

Если есть несколько подходящих аргументов, которые соответствуют типу неявного параметра, наиболее конкретный будет выбран с использованием правил статического перегрузочного разрешения (§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 Джоша вместо спецификации. Его разговор побудил меня взглянуть на это.

Внедрение компилятора

  • rankImplicits

    Я написал свой собственный ответ в виде сообщения в блоге, в котором не было изменений в импорте .

    Обновление : Кроме того, комментарии Мартина Одерского в вышеприведенной публикации показали, что поведение Scala 2.9.1, LocalIntFoo победой LocalIntFoo над ImportedIntFoo , на самом деле является ошибкой. См. Неявный приоритет параметра снова .

    • 1) подразумевает видимость текущей области вызова посредством локального объявления, импорта, внешней области, наследования, объекта пакета, доступного без префикса.
    • 2) неявная область , в которой содержатся всевозможные объекты-компаньоны и объект пакета, которые имеют некоторое отношение к типу-неявнику, который мы ищем (т. Е. Пакетный объект типа, сопутствующий объект самого типа, своего конструктора типов, если он есть, его параметры, если они есть, а также его супертип и супертрассы).

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

    Обновление 2 : Когда я спросил Джоша о Implicits без налога на импорт, он объяснил мне, что он ссылается на правила привязки имени для имплицитов, которые называются точно такими же .

    С http://www.scala-lang.org/docu/files/ScalaReference.pdf , глава 2:

    Имена в Scala определяют типы, значения, методы и classы, которые все вместе называются объектами. Имена вводятся локальными определениями и декларациями (§4), наследованием (§5.1.3), положениями о поставках (§4.7) или предложениями пакета (§9.2), которые все вместе называются связями.

    Привязки разных типов имеют приоритет, определенный для них: 1. Определения и декларации, которые являются локальными, унаследованными или доступными в соответствии с предложением пакета в том же компиляционном блоке, где имеет место определение, имеют наивысший приоритет. 2. Явный импорт имеет следующий высокий приоритет. 3. Импорт подстановочных знаков имеет следующий высокий приоритет. 4. Определения, предоставленные положением пакета, не входящим в блок компиляции, где имеет место определение, имеют наименьший приоритет.

    Я могу ошибаться, но вызов foo (1) находится в том же компиляционном блоке, что и LocalIntFoo, что приводит к тому, что преобразование имеет приоритет над ImportedIntFoo.

    Может ли кто-нибудь объяснить, как это считается более конкретным, используя «правила статического разрешения перегрузки (§6.26.3)»?

    Перегрузка метода отсутствует, поэтому 6.26.3 здесь совершенно неактуальен.

    Перегрузка относится к нескольким методам с тем же именем, но разные параметры определяются в одном classе. Например, метод f в примере 6.26.1 перегружен:

     class A extends B {} def f(x: B, y: B) = . . . def f(x: A, y: B) = . . . val a: A val b: B 

    Неявный приоритет разрешения параметров – это совершенно другое правило, и тот, у которого есть вопрос и ответ на Stack Overflow.

    Interesting Posts

    Включение / выключение состояния сеанса для каждого controllerа / метода действий

    React Native fetch () Ошибка сетевого запроса

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

    Два командных файла не будут работать вместе, в чем проблема?

    Как получить доступ к содержимому iframe с помощью jQuery?

    Как изменить цвет красной кнопки закрытия в Windows 8?

    Что означает «Метод» ~ ‘объекта’ ~ ‘failed?

    Сравнить два списка для поиска общих элементов

    Разница между getAttribute () и getParameter ()

    Предотвращение автоматического открытия Chrome автоматически загруженных файлов PDF и изображений

    Как пропустить Получить только свойства в servicestack json serializer?

    Расширение макроскопического расширения MSVC ++

    Языковые книги / Учебники для популярных языков

    Мониторы выключаются на секунду, Windows отключает устройство и подключает звук

    Как преобразовать float в int с Java

    Давайте будем гением компьютера.