A特质的自我类型:

trait B
trait A { this: B => }

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

另一方面,以下几点:

trait B
trait A extends B

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

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

我错过了什么?


当前回答

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
}

其他回答

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 A { self: B => }
trait B { self: A => }

使用extends的继承不允许这样。试一试:

trait A extends B
trait B extends A
error:  illegal cyclic reference involving trait A

在Odersky的书中,第33.5节(创建电子表格UI章节)提到:

在电子表格示例中,类Model继承自Evaluator和 从而获得其评价方法。同学们,走另一条路 Evaluator将自身类型定义为Model,如下所示:

package org.stairwaybook.scells
trait Evaluator { this: Model => ...

另一件没有提到的事情是:因为自类型不是所需类的层次结构的一部分,它们可以从模式匹配中排除,特别是当您根据密封的层次结构进行穷尽匹配时。当你想要建模正交行为时,这很方便,比如:

sealed trait Person
trait Student extends Person
trait Teacher extends Person
trait Adult { this : Person => } // orthogonal to its condition

val p : Person = new Student {}
p match {
  case s : Student => println("a student")
  case t : Teacher => println("a teacher")
} // that's it we're exhaustive

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

其他答案总结:

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