Scala 中的隐式抽象 class 构造函数参数和继承

Implicit abstract class constructor parameter and inheritance in Scala

我是 Scala 的新手,一直在尝试学习和理解隐式转换和参数,但遇到了一个让我感到困惑的场景。

对于上下文,我正在使用 Scaldi 在 Akka 应用程序中进行依赖注入,并希望有多个可注入的 actor 继承自抽象 class。我相信我无法使抽象 class 恰恰成为特征,因为我们需要通过构造函数参数使隐式 Injector 可用以利用框架。

展示我所看到的行为的一个非常人为的例子如下:

class SecretSauce {}

abstract class Base(implicit secretSauce: SecretSauce) {}

class Concrete extends Base {}

object Example extends App {
    ... // Setup Actor system, etc, etc
    implicit val secretSauce: SecretSauce = new SecretSauce()
}

我原以为一切正常,但我却收到编译错误:

Unspecified value parameter secretSauce.
class Concrete extends Base {
             ^

如果我将隐式参数添加到具体的 class,就像这样,事情会起作用:

class Concrete(implicit secretSauce: SecretSauce) extends Base {}

我认为我的困惑源于隐式参数的工作方式——在像我描述的那种情况下,它们不是由子 classes 继承的吗?有人可以 ELI5 我的例子中发生了什么,或者给我指出可以帮助解决问题的参考吗?

谢谢!

隐式参数从"resolved"获取:

  • 在当前作用域中定义的隐式
  • 显式导入
  • 通配符导入

据我了解,为了定义class Concrete,需要定义或导入隐式。

我在this SO answer中找到了很好的解释。

确定 Scala 编译器在何处查找隐式的确切规则有点复杂,但在大多数情况下,您只需要考虑隐式值可能来自的两个位置:

  1. 当前范围。
  2. 涉及的任何类型的伴随对象。

这意味着这将编译:

class SecretSauce {}

object SecretSauce {
  implicit val secretSauce: SecretSauce = new SecretSauce()
}

abstract class Base(implicit secretSauce: SecretSauce) {}

object Example extends App {
  class Concrete extends Base {}
}

或者这样:

class SecretSauce {}

abstract class Base(implicit secretSauce: SecretSauce) {}

object Example extends App {
  implicit val secretSauce: SecretSauce = new SecretSauce()

  class Concrete extends Base {}
}

但是,在您的版本中,当编译器到达这一行时:

class Concrete extends Base {}

它会知道它需要找到一个隐式 SecretSauce 值,它会首先查看范围 中那一行 中的隐式值,然后在SecretSauce 伴生对象(如果存在)。它也没有找到,所以它拒绝编译你的代码。