【问题标题】:Why does this explicit call of a Scala method allow it to be implicitly resolved?为什么这个 Scala 方法的显式调用允许它被隐式解析?
【发布时间】:2011-02-13 10:37:31
【问题描述】:

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

【问题讨论】:

    标签: scala scala-2.8 implicit


    【解决方案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) {}
        }
      }
    }
    

    bar 之前定义Implicits 也可以:

    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

    【讨论】:

    • 它是(应该是)规范的。保尔普最近发现了一张如此程度的票。让我看看是不是找不到...
    【解决方案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 放在首位,它会起作用。对我来说,这在进行多个编译器传递的逻辑中看起来像是一个错误;它假设它可以在编译bar 时在不真正了解string2Wrapper 的情况下逃脱。我的猜测是,如果你使用它,它知道它无法摆脱不知道 string2Wrapper 到底是什么,实际上编译了Implicits,然后意识到==&gt; 是隐式定义在String 上的。

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

      【讨论】:

        猜你喜欢
        • 2012-08-04
        • 2017-02-24
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-08-04
        相关资源
        最近更新 更多