A特质的自我类型:

trait B
trait A { this: B => }

他说:“A不能被混合到一个具体的类中,这个类不能同时扩展B。”

另一方面,以下几点:

trait B
trait A extends B

表示“任何(具体或抽象的)类在A中混合也会在B中混合”。

这两句话的意思难道不是一样的吗?自我类型似乎只用于产生简单的编译时错误的可能性。

我错过了什么?


当前回答

其他答案总结:

扩展的类型公开给继承的类型,但自类型不是 class Cow {this: FourStomachs}允许你使用只适用于反刍动物的方法,如digestGrass。扩展牛的特性将没有这样的特权。另一方面,类Cow扩展four胃部会将digestGrass暴露给任何扩展Cow的人。 自类型允许循环依赖,而扩展其他类型则不允许

其他回答

trait A { def x = 1 }
trait B extends A { override def x = super.x * 5 }
trait C1 extends B { override def x = 2 }
trait C2 extends A { this: B => override def x = 2}

// 1.
println((new C1 with B).x) // 2
println((new C2 with B).x) // 10

// 2.
trait X {
  type SomeA <: A
  trait Inner1 { this: SomeA => } // compiles ok
  trait Inner2 extends SomeA {} // doesn't compile
}

self类型允许您指定允许在trait中混合哪些类型。例如,如果你有一个带有self类型Closeable的trait,那么这个trait知道唯一允许混合它的东西必须实现Closeable接口。

让我们从周期依赖开始。

trait A {
  selfA: B =>
  def fa: Int }

trait B {
  selfB: A =>
  def fb: String }

然而,这个解决方案的模块化并不像它看起来那么好,因为你可以像这样重写自我类型:

trait A1 extends A {
  selfA1: B =>
  override def fb = "B's String" }
trait B1 extends B {
  selfB1: A =>
  override def fa = "A's String" }
val myObj = new A1 with B1

但是,如果重写了self类型的成员,就失去了对原始成员的访问权,仍然可以通过super using继承访问原始成员。因此,通过使用继承真正获得的是:

trait AB {
  def fa: String
  def fb: String }
trait A1 extends AB
{ override def fa = "A's String" }        
trait B1 extends AB
{ override def fb = "B's String" }    
val myObj = new A1 with B1

现在我不能说我已经理解了饼模式的所有微妙之处,但是我突然意识到,加强模块化的主要方法是通过组合而不是继承或自我类型。

继承版本更短,但我更喜欢继承而不是自我类型的主要原因是,我发现对自我类型进行正确的初始化顺序要棘手得多。然而,有些事情你可以用自我类型做,而不能用继承做。自我类型可以使用类型,而继承需要一个trait或类,如下所示:

trait Outer
{ type T1 }     
trait S1
{ selfS1: Outer#T1 => } //Not possible with inheritance.

你甚至可以这样做:

trait TypeBuster
{ this: Int with String => }

尽管您永远无法实例化它。我没有看到任何绝对的理由不能够从一个类型继承,但我肯定认为它将有用的路径构造函数类和特征,因为我们有类型构造函数特征/类。是不幸的

trait InnerA extends Outer#Inner //Doesn't compile

我们有这个:

trait Outer
{ trait Inner }
trait OuterA extends Outer
{ trait InnerA extends Inner }
trait OuterB extends Outer
{ trait InnerB extends Inner }
trait OuterFinal extends OuterA with OuterB
{ val myV = new InnerA with InnerB }

或:

  trait Outer
  { trait Inner }     
  trait InnerA
  {this: Outer#Inner =>}
  trait InnerB
  {this: Outer#Inner =>}
  trait OuterFinal extends Outer
  { val myVal = new InnerA with InnerB with Inner }

我们应该更多地理解的一点是,特征可以扩展阶级。感谢David Maclver指出这一点。下面是我自己代码中的一个例子:

class ScnBase extends Frame
abstract class ScnVista[GT <: GeomBase[_ <: TypesD]](geomRI: GT) extends ScnBase with DescripHolder[GT] )
{ val geomR = geomRI }    
trait EditScn[GT <: GeomBase[_ <: ScenTypes]] extends ScnVista[GT]
trait ScnVistaCyl[GT <: GeomBase[_ <: ScenTypes]] extends ScnVista[GT]

ScnBase继承自Swing Frame类,因此它可以用作self类型,然后在最后(实例化时)混合使用。然而,val geomR在被继承trait使用之前需要初始化。所以我们需要一个类来强制先行初始化geomR。ScnVista类可以被多个正交特征继承,这些特征本身也可以被继承。使用多个类型参数(泛型)提供了另一种模块化形式。

在第一种情况下,B的一个子特征或子类可以混合到任何使用a的地方,所以B可以是一个抽象的特征。

其他答案总结:

扩展的类型公开给继承的类型,但自类型不是 class Cow {this: FourStomachs}允许你使用只适用于反刍动物的方法,如digestGrass。扩展牛的特性将没有这样的特权。另一方面,类Cow扩展four胃部会将digestGrass暴露给任何扩展Cow的人。 自类型允许循环依赖,而扩展其他类型则不允许