Почему это кодирует сбой для компиляции, но компиляции успешно, когда я некомментирую обозначенную строку? (Я использую 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) {}
}
}
}
Править: спасибо за ответы до сих пор, которые включают указатель на комментарий Martin Odersky,
"Неявное преобразование без явного типа результата видимо только в тексте после его собственного определения. Тем путем мы избегаем циклических ссылочных ошибок".
Я все еще интересовался бы обнаружением 1) какова опасность "циклических ссылочных ошибок"? и 2) Почему явный вызов имеет какое-либо значение?
Явное приписывание типа возвращаемого значения 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) {}
}
}
}
Определение Имплицитов
перед 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
.
ОБНОВЛЕНИЕ
В чем опасность ошибки циклического задания?
Тело неявного метода может вызывать метод, требующий неявного преобразования. Если у обоих из них есть предполагаемый тип возврата, вы в тупике. Это не относится к вашему примеру, но компилятор не пытается это обнаружить.
Почему явный вызов имеет значение?
Явный вызов ранее запускает вывод типа возвращаемого типа неявного метода. Вот логика в Implicits.isValid
sym.isInitialized ||
sym.sourceFile == null ||
(sym.sourceFile ne context.unit.source.file) ||
hasExplicitResultType(sym) ||
comesBefore(sym, context.owner)
UPDATE 2
Эта недавняя ошибка выглядит актуальной: https://lampsvn.epfl.ch/trac/scala/ticket/3373
Если бы вы были на ooooone ночью позже, вы бы вместо этого увидели сообщение об ошибке, которое я добавил вчера.
<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"
^
Если сначала поставить объект Implicits
, это сработает. Мне это кажется ошибкой в логике выполнения нескольких проходов компилятора; он предполагает, что может обойтись, не зная о string2Wrapper
при компиляции bar
. Я предполагаю, что если вы его используете, он знает, что не может уйти, не зная, что такое string2Wrapper на самом деле, на самом деле компилирует Implicits
, а затем понимает, что ==>
неявно определено в String.
Редактировать: Судя по тому, что опубликовал Retronym, возможно, это «особенность», а не ошибка. Мне все еще кажется странным!