如何将traits声明为隐含的"构造函数参数"?

And*_*yle 36 scala implicit traits

我正在设计一个类层次结构,它由一个基类和几个特征组成.基类提供了几种方法的默认实现,并且traits选择性地覆盖某些方法abstract override,以便充当可堆叠的traits/mixins.

从设计的角度来看,这很有效,并映射到域,以便我可以从这里添加过滤函数(一个特征),带有来自此处的谓词(另一个特征)等.

但是,现在我想要一些我的特征来采用隐式参数.我很高兴从设计的角度来看这仍然有意义,并且在实践中不会让人感到困惑.但是,我不能说服编译器运行它.

问题的核心似乎是我无法为特征提供构造函数参数,因此可以将它们标记为隐式.在方法实现中引用隐式参数无法使用预期的"无法找到隐式值"消息进行编译; 我试图通过构建阶段(在实践中,它总是在范围内)"隐藏"隐含的方法,以便在方法中可用

implicit val e = implicitly[ClassName]
Run Code Online (Sandbox Code Playgroud)

但是(毫无疑问,你们很多人都希望)这个定义失败了同样的信息.

似乎这里的问题是我无法说服编译器用implicit ClassName标志标记特征本身的签名,并强制调用者(即将特征混合到一个对象中的那些)来提供隐式.目前我的调用者正在这样做,但编译器没有在此级别进行检查.


是否有任何方法可以将特征标记为在施工时需要某些隐含物?

(如果不是,这还没有实现,还是有更深层次的原因,为什么这是不切实际的?)

Ale*_*nov 16

实际上,我之前经常想要这个,但我想出了这个想法.你可以翻译

trait T(implicit impl: ClassName) {
  def foo = ... // using impl here
}
Run Code Online (Sandbox Code Playgroud)

to [EDITED:原始版本没有为其他方法提供隐式访问]

trait T {
  // no need to ever use it outside T
  protected case class ClassNameW(implicit val wrapped: ClassName)

  // normally defined by caller as val implWrap = ClassNameW 
  protected val implWrap: ClassNameW 

  // will have to repeat this when you extend T and need access to the implicit
  import implWrap.wrapped

  def foo = ... // using wrapped here
}
Run Code Online (Sandbox Code Playgroud)

  • 当然,我很乐意看到更好的解决方案. (9认同)

Pau*_*per 14

这是不可能的.

但是您可以使用implicitlyScala的类型推断来尽可能轻松.

trait MyTrait {

    protected[this] implicit def e: ClassName

}
Run Code Online (Sandbox Code Playgroud)

然后

class MyClass extends MyTrait {

    protected[this] val e = implicitly // or def

}
Run Code Online (Sandbox Code Playgroud)

简洁,甚至不需要在扩展类中编写类型.


Bla*_*ade 11

我遇到过这个问题几次,确实有点烦人,但不是太多.摘要成员和参数通常是做同样事情的两种替代方式,各有利弊; 对于具有抽象成员的特征并不太不方便,因为无论如何你还需要另一个类来实现这个特征.*

因此,您应该在特征中简单地使用抽象值声明,以便实现类必须为您提供隐式.请参阅以下示例 - 它正确编译,并显示了实现给定特征的两种方法:

trait Base[T] {
    val numT: Ordering[T]
}
/* Here we use a context bound, thus cannot specify the name of the implicit
 * and must define the field explicitly.
 */
class Der1[T: Ordering] extends Base[T] {
    val numT = implicitly[Ordering[T]]
    //Type inference cannot figure out the type parameter of implicitly in the previous line
}
/* Here we specify an implicit parameter, but add val, so that it automatically
 * implements the abstract value of the superclass.
 */
class Der2[T](implicit val numT: Ordering[T]) extends Base[T]
Run Code Online (Sandbox Code Playgroud)

我展示的基本思想也出现在Knut Arne Vedaa的答案中,但我试图制作一个更引人注目且更方便的例子,不再使用不需要的功能.

*这不是特质不能接受参数的原因 - 我不知道.我只是在争论这种限制在这种情况下是可以接受的.

  • 但是,这样在定义`Base [T]`中的方法时,您无法访问隐式`Ordering [T]`.如果你使`numT`隐式,你修复_this_问题,但`val numT =隐式[Ordering [T]]`变成一个无限循环. (2认同)