私はScalaで暗黙のパラメーターがどのように機能するかを把握しようとしています。私が知る限り、暗黙のパラメータ解決は次のようになります。
- オブジェクトをメソッドに明示的に渡します。
- スコープで定義された暗黙の定義。
- 暗黙のパラメータとして使用されるクラスのコンパニオンオブジェクト
しかし、怠惰なvalsと組み合わせてこれをいじり始めたとき、私は少し驚きました。怠惰なvalsは最後の解決ルールのみを使用するようです。説明のためのサンプルコードを次に示します。
class Bar(val name:String)
object Bar { implicit def bar = new Bar("some default bar") }
class Foo {
lazy val list = initialize
def initialize(implicit f:Bar) = {
println("initialize called with Bar: '" + f.name + "' ...")
List[Int]()
}
}
trait NonDefaultBar extends Foo {
implicit def f = new Bar("mixed in implicit bar")
def mixedInInit = initialize
lazy val mixedInList = list
}
object Test {
def test = {
println("Case 1: with implicitp parameter from companion object")
val foo1 = new Foo
foo1.list
foo1.initialize
println("Case 2: with mixedin implicit parameter overriding the default one...")
val foo2 = new Foo with NonDefaultBar
foo2.mixedInList
val foo3 = new Foo with NonDefaultBar
foo3.mixedInInit
println("Case 3: with local implicit parameter overriding the default one...")
implicit def nonDefaultBar = new Bar("locally scoped implicit bar")
val foo4 = new Foo
foo4.list
foo4.initialize
}
}
呼び出すTest.test
と、次の出力が得られます。
Case 1: with implicitp parameter from companion object
initialize called with Bar: 'some default bar' ...
initialize called with Bar: 'some default bar' ...
Case 2: with mixedin implicit parameter overriding the default one...
initialize called with Bar: 'some default bar' ...
initialize called with Bar: 'mixed in implicit bar'...
Case 3: with local implicit parameter overriding the default one...
initialize called with Bar: 'some default bar' ...
initialize called with Bar: 'locally scoped implicit bar' ...
ケース2でmixedInListを呼び出すときに、コンパイラが暗黙のバーが混在していることをキャッチしないのはなぜですか。ケース3では、リストにアクセスするときにローカルで定義された暗黙のバーも見逃されます。
コンパニオンオブジェクトで定義された暗黙を使用しない遅延値で暗黙のパラメーターを使用する方法はありますか?