我正在尝试使用隐式参数将依赖项“注入”我的类,如下所示:
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隐含参数的已知限制?
答案 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