Почему этот явный вызов метода Scala позволяет неявно разрешать его?
Почему этот код не скомпилирован, но успешно компилируется, когда я раскомментирую указанную строку? (Я использую Scala 2,8 в ночное время). Кажется, что явно вызов string2Wrapper
позволяет использовать его неявно с этой точки.
class A {
import Implicits.string2Wrapper
def foo() {
//string2Wrapper("A") ==> "B" // <-- uncomment
}
def bar() {
"A" ==> "B"
"B" ==> "C"
"C" ==> "D"
}
object Implicits {
implicit def string2Wrapper(s: String) = new Wrapper(s)
class Wrapper(s: String) {
def ==>(s2: String) {}
}
}
}
Изменить: спасибо за ответы до сих пор, в том числе указатель на комментарий Мартина Одерского,
"Неявное преобразование без явного типа результата видимо только в тексте следуя собственному определению. Таким образом, мы избегаем циклических ошибок ссылки.
Мне все равно было бы интересно узнать 1), какова опасность "циклических эталонных ошибок"?, и 2) Почему явный вызов имеет какое-то значение?
Ответы
Ответ 1
Явная привязка возвращаемого типа string2Wrapper устраняет проблему.
class A {
import Implicits._
def bar() {
"A" ==> "B"
"B" ==> "C"
"C" ==> "D"
}
object Implicits {
implicit def string2Wrapper(s: String): Wrapper = new Wrapper(s)
class Wrapper(s: String) {
def ==>(s2: String) {}
}
}
}
Определение Implicits
до bar
также работает:
class A {
object Implicits {
implicit def string2Wrapper(s: String) = new Wrapper(s)
class Wrapper(s: String) {
def ==>(s2: String) {}
}
}
import Implicits._
def bar() {
"A" ==> "B"
"B" ==> "C"
"C" ==> "D"
}
}
Если вам нужно полагаться на неявное преобразование, определенное ниже в текущей области, убедитесь, что вы аннотируете его тип возврата. Довольно точно, что это появилось в списках рассылки раньше, и может ожидаться поведение, а не ошибка. Но я не могу найти его в данный момент. Я предполагаю, что явный вызов в foo
запускает вывод типа возвращаемого типа bar
, который тогда действителен при вводе содержимого bar
.
UPDATE
В чем опасность циклической ошибки ссылки?
Тело неявного метода может вызывать метод, который требует неявного преобразования. Если у обоих из них есть предполагаемый тип возврата, вы находитесь в тупике. Это не применяется в вашем примере, но компилятор не пытается обнаружить это.
Почему явный вызов имеет значение?
Явный вызов ранее запускает вывод типа возвращаемого типа неявного метода. Здесь логика в Implicits.isValid
sym.isInitialized ||
sym.sourceFile == null ||
(sym.sourceFile ne context.unit.source.file) ||
hasExplicitResultType(sym) ||
comesBefore(sym, context.owner)
ОБНОВЛЕНИЕ 2
Эта недавняя ошибка выглядит актуальной: https://lampsvn.epfl.ch/trac/scala/ticket/3373
Ответ 2
Если бы вы были просто ооооодно ночью позже, вы бы вместо этого увидели сообщение об ошибке, которое я добавил вчера.
<console>:11: error: value ==> is not a member of java.lang.String
Note: implicit method string2Wrapper is not applicable here because it comes after the application point and it lacks an explicit result type
"A" ==> "B"
^
<console>:12: error: value ==> is not a member of java.lang.String
Note: implicit method string2Wrapper is not applicable here because it comes after the application point and it lacks an explicit result type
"B" ==> "C"
^
<console>:13: error: value ==> is not a member of java.lang.String
Note: implicit method string2Wrapper is not applicable here because it comes after the application point and it lacks an explicit result type
"C" ==> "D"
^
Ответ 3
Если вы положили object Implicits
во-первых, он работает. Это выглядит как ошибка для меня в логике для создания нескольких прогонов компилятора; он предполагает, что он может уйти, не зная о string2Wrapper
при компиляции bar
. Я предполагаю, что, если вы его используете, он знает, что не может уйти, не зная, что такое string2Wrapper, на самом деле компилирует Implicits
, а затем понимает, что ==>
неявно определяется в String.
Изменить: на основании того, что опубликовал Retronym, возможно, это "функция", а не ошибка. Мне все еще кажется нелепым!