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

在这里,编译器从伴随对象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伴随对象来解析隐式参数之前查看。这篇博文指出:

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

我是否遗漏了什么,或者这是 scalas 隐式参数的已知限制?

4

1 回答 1

9

调用aBar是在内部定义的FooTrait。当这个 trait 编译时,本地范围、封闭类或父类中没有适当的隐式。当您稍后混合另一个特征时,编译器不会尝试重新查找隐含。所以它只使用伴随对象的默认隐式。

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 回答