超特征的隐式参数解析

时间:2012-05-03 11:23:56

标签: scala implicit

我正在尝试使用隐式参数将依赖项“注入”我的类,如下所示:

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 }
}

这里编译器从FooTrait的伴随对象中的隐式val向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。这blog post个州:

  

对于要应用隐式值的规则非常严格   到一个隐含的参数。思考它的一个简单方法就是   将使用“最接近”的定义。本地范围,封闭类,   父类,所需类型的伴随对象。

我是否遗漏了某些内容,或者这是scalas隐含参数的已知限制?

1 个答案:

答案 0 :(得分:8)

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