2012-01-13 14 views
7

をループの結果:なぜこれらの暗黙的な変換は、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) 
    } 
} 

コードをループで暗黙の使用の結果。実際には、disassemblyingは明らかに、変換方法を生成し、その内部にのみgoto 0を持っている:

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

public Test$BI BtoBI(Test$B); 
    Code: 
    0: goto 0 

その行動の原因は何?ここでのクラスの階層は疑わしいですが、暗黙的な変換は一度だけ適用する必要があります。

私は、コードがすべてでコンパイル、なぜ私が理解できないのScala 2.9.1

+2

コードがすべてでコンパイル、なぜ私が理解することはできませんが(私はそれは* *コンパイルないことを確認し)。暗黙的な変換方法の中でダウンキャストする必要はありませんか? – ziggystar

+0

実際、私もどちらも。これは、コードの大部分から分離されたケースです。 –

答えて

12

私は間違いなくそれをバグと呼んでいません。

それはどのような方法で関連する変換の両側のための必要はありません

class A 

class B 

implicit def aToB(a: A) : B = a 

に沸きます。暗黙のは、コンパイラが必要な戻り値の型Bに結果aを変換するためにaToB呼び出しを挿入するため

implicit def aToB(a: A): B = aToB(a) 

を書くとちょうど同じことです。

goto 0の実装は、テールコールの最適化に過ぎません。この方法で始まるメソッドを生成すると、コンパイラはおそらく警告を出します。

おそらく暗黙的なメソッドが自分の体の中の暗黙的なメソッドとして利用できないというルールがあるかもしれません。しかし、それは常に(OK、これは単なるmap(toB)ある)

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

無限ループを作成しません。とにかく、同じことが2つの相互に再帰的な意味で起こる可能性があります。私の意見では、無限を書く何かの可能性を避けるために仕様を微調整するだけの価値はないと思います。しかし、そのようなループが検出されたときに、暗黙にかかわらず警告がうまくいくでしょう。

+0

ニースの答え! o/cU – ron

+0

答えをありがとう! –

2

を使用しています。私はそれがコンパイルされることを確認した。暗黙的な変換方法の中でダウンキャストする必要はありませんか?

暗黙の変換が再帰的に適用されることを指摘します。つまり、コードはダウンキャストなしでコンパイルできます。

次のコードは、ダウンキャストを追加します(は実行時の動作を変更しません)。実行時に失敗したキャストで失敗します。 これはコンパイラのバグのようです。 ディディエは言うように、明示的なダウンキャストはここで暗黙の変換の再帰的な適用を防ぎます。

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.asInstanceOf[AI] 

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

    implicit def BtoBI(b: B): BI = b.asInstanceOf[BI] 

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

    val b = new B 
    println(b.sayHello) 
    } 
} 

質問に答えることにより、仕上げ:あなたは、このメソッドを持たないクラス Aの対象に AIのメソッドを呼び出します。明らかに、これは機能しません。何が起こるかは不明です。あなたの場合、それは無限ループでした。

+1

ダウンキャストでは、暗黙の変換を挿入しようとしないため、(失敗した)ダウンキャストを追加すると動作が変更されます。 –

+0

答えをありがとう! –

関連する問題