Почему этот явный вызов метода Scala позволяет его неявно разрешить? - PullRequest
16 голосов
/ 28 апреля 2010

Почему этот код не компилируется, но компилируется успешно, когда я раскомментирую указанную строку? (Я использую 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) Почему явный вызов имеет значение?

Ответы [ 3 ]

21 голосов
/ 28 апреля 2010

Явное присвоение возвращаемого типа 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

12 голосов
/ 28 апреля 2010

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

<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 голосов
/ 28 апреля 2010

Если сначала поставить object Implicits, это сработает. Это выглядит для меня как ошибка в логике создания нескольких проходов компилятора; он предполагает, что может обойтись без реального знания о string2Wrapper при компиляции bar. Я предполагаю, что если вы используете его, он знает, что не может обойтись без знания того, что такое string2Wrapper, на самом деле компилирует Implicits, а затем понимает, что ==> неявно определен в String.

Редактировать: Судя по тому, что опубликовал Retronym, возможно, это «особенность», а не ошибка. Тем не менее, мне кажется, что он негодяй!

...