5

私は暗黙のパラメータを使用して、次のように依存関係をクラスに「注入」しようとしています。

trait Bar {
    def m:String
}

object Bar {
    implicit val objBar = new Bar{ val m = "from object" } 
}

trait FooTrait { 
    def aBar(implicit bar:Bar) = bar
    def go = { aBar.m }
}

ここで、コンパイラは、コンパニオンオブジェクトの暗黙のFooTraitvalからに暗黙の引数を提供します。Barそうすること:

scala> println((new FooTrait{}).go)
from object

期待する結果が得られます。ただし、FooTraitと次のような別の特性を組み合わせると次のようになります。

trait SuperFoo {
    implicit val superBar = new Bar{ val m = "from super" }
}

結果は同じです:

scala> println((new FooTrait with SuperFoo).go)
from object

コンパイラは、のコンパニオンオブジェクトSuperFooをチェックして暗黙の引数を解決しようとする前に、前を調べると思いました。Barこのブログ投稿は次のように述べています。

暗黙の値が暗黙のパラメーターに適用される非常に厳密な規則があります。それについて考える簡単な方法は、「最も近い」定義が使用されるということです。ローカルスコープ、包含クラス、親クラス、目的のタイプのコンパニオンオブジェクト。

私は何かが足りないのですか、それともこれはscalasの暗黙のパラメーターの既知の制限ですか?

4

1 に答える 1

9

呼び出し先aBarは内で定義されFooTraitます。このトレイトがコンパイルされるとき、ローカルスコープ、囲んでいるクラス、または親クラスに適切な暗黙はありません。コンパイラは、後で別のトレイトをミックスするときに、暗黙的なものを再検索しようとはしません。したがって、コンパニオンオブジェクトからのデフォルトの暗黙を使用します。

SuperFooメソッドをオーバーライドすると、から値を取得できgoます。

scala> println((new FooTrait with SuperFoo {override def go = {aBar.m}}).go)
from super

クラス階層を再定義して、親の特性から暗黙的に取得することもできます。

trait BarHolder { 
    implicit val superBar: Bar
}
trait FooTrait extends BarHolder { 
    def aBar(implicit bar:Bar) = bar
    def go = { aBar.m }
}
trait DefaultFoo extends BarHolder {
    val superBar = implicitly[Bar]
}
trait SuperFoo extends BarHolder {
    val superBar = new Bar{ val m = "from super" }
}

そしてそれをこのように使用します:

scala> println((new FooTrait with DefaultFoo).go)
from object

scala> println((new FooTrait with SuperFoo).go)
from super
于 2012-05-03T13:38:30.983 に答える