为什么Scala方法的显式调用允许隐式解析?

时间:2010-04-28 16:07:02

标签: scala scala-2.8 implicit

为什么此代码无法编译,但在取消注释指示的行时成功编译? (我每晚都使用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)为什么显式调用有什么不同?

3 个答案:

答案 0 :(得分:20)

明确归因于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的内容时有效。

<强>更新

  

循环参考错误有什么危险?

隐式方法的主体可以调用需要隐式转换的方法。如果这两个都具有推断的返回类型,那么你就陷入了僵局。这不适用于您的示例,但编译器不会尝试检测此。

  

为什么显式通话会产生影响?

先前的显式调用触发隐式方法的返回类型的类型推断。这是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

答案 1 :(得分: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"
           ^

答案 2 :(得分:3)

如果你先放object Implicits,它就可以了。对于我来说,这在编写多个编译器通道的逻辑中看起来像个错误;它假设在编译string2Wrapper时不知道bar就可以逃脱。我的猜测是,如果你使用它,它知道它不能逃脱不知道string2Wrapper究竟是什么,实际编译Implicits,然后意识到==>是在String上隐式定义的。

编辑:根据Retronym发布的内容,也许这是一个“功能”而非错误。对我来说似乎仍然很棘手!