超特征的隐式参数解析

Emi*_*l H 4 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 }
}
Run Code Online (Sandbox Code Playgroud)

这里编译器FooTraitBar伴随对象中的隐式val 提供隐式参数.这样做:

scala> println((new FooTrait{}).go)
from object
Run Code Online (Sandbox Code Playgroud)

给我我期望的结果.但是,如果我混合FooTrait和另一个特征如:

trait SuperFoo {
    implicit val superBar = new Bar{ val m = "from super" }
}
Run Code Online (Sandbox Code Playgroud)

结果是一样的:

scala> println((new FooTrait with SuperFoo).go)
from object
Run Code Online (Sandbox Code Playgroud)

我认为编译器会SuperFoo在尝试通过检查Bar的伴随对象来解析隐式参数之前查看.这篇博客文章指出:

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

我错过了什么或者这是scalas隐含参数的已知限制吗?

inc*_*rop 8

呼叫aBar是在里面定义的FooTrait.当此特征编译时,本地范围,封闭类或父类中没有正确的含义.当您稍后混入其他特征时,编译器不会尝试重新发现隐含.所以它只使用来自伴随对象的默认隐式.

SuperFoo如果覆盖方法,则可以获取值go:

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

您还可以重新定义类层次结构以获取隐式父级特征:

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" }
}
Run Code Online (Sandbox Code Playgroud)

并以这种方式使用它:

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

scala> println((new FooTrait with SuperFoo).go)
from super
Run Code Online (Sandbox Code Playgroud)