18

为什么这段代码编译失败,但是当我取消注释指示的行时编译成功?(我每晚都使用 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)为什么显式调用会产生任何影响?

4

3 回答 3

21

显式指定 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) {}
    }
  }
}

定义Implicitsbeforebar也有效:

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)

更新 2

这个最近的错误看起来很相关:https ://lampsvn.epfl.ch/trac/scala/ticket/3373

于 2010-04-28T16:19:23.893 回答
12

如果您只是晚一点,您会看到我昨天添加的错误消息。

<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"
           ^
于 2010-04-28T18:32:04.430 回答
3

如果你把object Implicits它放在第一位,它会起作用。对我来说,这在进行多个编译器传递的逻辑中看起来像是一个错误;它假设它可以在不真正知道string2Wrapper何时编译的情况下逃脱bar。我的猜测是,如果你使用它,它知道它无法逃避不知道 string2Wrapper 到底是什么,实际编译Implicits,然后意识到这==>是在 String 上隐式定义的。

编辑:根据Retronym 发布的内容,也许这是一个“功能”而不是一个错误。在我看来仍然很古怪!

于 2010-04-28T16:22:08.513 回答