蛋糕模式中显式类型自引用的有用性

时间:2012-07-13 00:57:46

标签: scala cake-pattern

似乎Scala的explicitly-typed self references最常见的用法是“Cake pattern”,其中模块的依赖关系被声明为:

class Foo { this: A with B with C =>
  // ...
}

通常,暂时忽略蛋糕模式,ABC可以引用任何类型级别的内容,例如类型参数:

class Outer[A, B, C] {
  class Inner { this: A with B with C =>
    // ...
  }
}

...或抽象类型成员:

class Outer {
  type A
  type B
  type C
  class Inner { this: A with B with C =>
    // ...
  }
}

在这两种情况下,我们都不能写abstract class Inner extends A with B with C,因为ABC不是特征。这里需要明确键入的自引用。但是,我只见过用特征完成的蛋糕模式:

trait A { def a }
trait B { def b }
trait C { def c }
class Foo { this: A with B with C =>
  // ...
}

在这种情况下,我们可以直接写abstract class Foo extends A with B with C,如果我没有弄错,它具有相同的含义。我对么?如果没有,那么他们如何区别;如果是这样,为什么每个人似乎都使用明确类型的自引用?

2 个答案:

答案 0 :(得分:6)

似乎我忽略了两个主要的区别:

  1. 虽然明确的自我类型注释和简单的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.
    

    这是一件好事,因为在蛋糕模式中你不想要你的&#34;模块&#34;对象无意中,多态地用作它所依赖的特征之一。

  2. As noted explicitly by Mushtaqindirectly by Daniel,在使用自我类型注释时,依赖关系可以是循环的。循环依赖是非常常见的,并且不一定是坏的(假设相互依赖的组件不需要彼此进行初始化,或者我们可以在它们之间以某种方式tie the knot),所以这是自我类型的另一个明显好处继承注释。

答案 1 :(得分:1)

使用继承时,可以决定初始化顺序。当您使用自我类型时,请将其保持打开状态。

还有其他差异,但我认为其中大多数都是实施细节,可能会消失。我知道其中一些是。