mer*_*ict 7 scala cake-pattern
似乎Scala的显式类型自引用最常见的用法是" Cake模式 ",其中模块的依赖项声明如下:
class Foo { this: A with B with C =>
// ...
}
Run Code Online (Sandbox Code Playgroud)
通常,暂时忽略蛋糕模式A
,B
并且C
可以引用任何类型级别的东西,例如类型参数:
class Outer[A, B, C] {
class Inner { this: A with B with C =>
// ...
}
}
Run Code Online (Sandbox Code Playgroud)
......或抽象类型的成员:
class Outer {
type A
type B
type C
class Inner { this: A with B with C =>
// ...
}
}
Run Code Online (Sandbox Code Playgroud)
在这些情况中,我们都不能写abstract class Inner extends A with B with C
,因为A
,B
并且C
不知道是特征.这里需要明确键入的自引用.但是,我只见过用特征完成的蛋糕模式:
trait A { def a }
trait B { def b }
trait C { def c }
class Foo { this: A with B with C =>
// ...
}
Run Code Online (Sandbox Code Playgroud)
在这种情况下,我们可以abstract class Foo extends A with B with C
直接写,如果我没有弄错,它具有相同的含义.我对么?如果没有,那么他们如何区别; 如果是这样,为什么每个人似乎都使用明确类型的自引用?
似乎我忽略了两个主要的区别:
虽然显式自我类型注释和简单extends
关键字都描述了两种类型之间的"is-a"关系,但在前一种情况下,该关系在外部并不可见:
scala> trait T
defined trait T
scala> class C { this: T => }
defined class C
scala> implicitly[C <:< T]
<console>:10: error: Cannot prove that C <:< T.
Run Code Online (Sandbox Code Playgroud)
这是一件好事,因为在蛋糕模式中你不希望你的"模块"对象无意中被多态地用作它所依赖的特征之一.
如明确穆什塔克指出和由Daniel间接,依赖关系可以使用自式注释时,是环状的.循环依赖是非常常见的,并且不一定是坏的(假设相互依赖的组件不需要彼此进行初始化,或者我们可以以某种方式将它们绑定在它们之间),所以这是自我类型注释相对于继承的另一个明显好处.