为什么这些隐式转换导致循环代码

Raf*_*cki 7 scala implicit

考虑使用Scala中的以下代码:

object Test {
  class A {}

  class B extends A {}

  class AI extends A {
    def sayHello: String = "Hello from AI"
  }

  implicit def AtoAI(a: A): AI = a

  class BI extends B {
    def sayHello: String = "Hello from BI"
  }

  implicit def BtoBI(b: B): BI = b

  def main(args: Array[String]) {
    val a = new A
    println(a.sayHello)

    val b = new B
    println(b.sayHello)
  }
}
Run Code Online (Sandbox Code Playgroud)

使用implicits会导致循环代码.事实上,反汇编表明,生成的转换方法只有一个goto 0内部:

public Test$AI AtoAI(Test$A);
  Code:
   0:   goto    0

public Test$BI BtoBI(Test$B);
  Code:
   0:   goto    0
Run Code Online (Sandbox Code Playgroud)

是什么导致这种行为?我理解,这里的类层次结构是可疑的,但隐式转换只应用一次.

我使用Scala 2.9.1

Did*_*ont 12

不好,但我绝对不会称之为bug.

归结为

class A

class B

implicit def aToB(a: A) : B = a
Run Code Online (Sandbox Code Playgroud)

转换的双方无需以任何方式相关.隐含与写作是一回事

implicit def aToB(a: A): B = aToB(a)
Run Code Online (Sandbox Code Playgroud)

因为编译器插入aToB调用以将结果转换a为所需的返回类型B.

goto 0实施只是一个尾部调用优化.编译器在生成以这种方式启动的方法时可能会发出警告.

也许可能存在一种规则,即隐含的方法不能作为其自身体内的含义.但它并不总是创造一个无限循环

implicit def listAToListB(l: list[A] = l match {
  case Nil => Nil
  case x:xs => toB(x) :: xs // equivalent to toB(x) :: listAToList[B](xs)
}
Run Code Online (Sandbox Code Playgroud)

(好吧,这只是一个map(toB)).无论如何,两个相互递归的暗示也会发生同样的情况.在我看来,调整规范是不值得的,只是为了避免一些写无限循环的可能性,以及其他许多循环.但是当检测到这样的循环时,无论含义如何,都会发出警告.