A特质的自我类型:
trait B
trait A { this: B => }
他说:“A不能被混合到一个具体的类中,这个类不能同时扩展B。”
另一方面,以下几点:
trait B
trait A extends B
表示“任何(具体或抽象的)类在A中混合也会在B中混合”。
这两句话的意思难道不是一样的吗?自我类型似乎只用于产生简单的编译时错误的可能性。
我错过了什么?
A特质的自我类型:
trait B
trait A { this: B => }
他说:“A不能被混合到一个具体的类中,这个类不能同时扩展B。”
另一方面,以下几点:
trait B
trait A extends B
表示“任何(具体或抽象的)类在A中混合也会在B中混合”。
这两句话的意思难道不是一样的吗?自我类型似乎只用于产生简单的编译时错误的可能性。
我错过了什么?
当前回答
另一件没有提到的事情是:因为自类型不是所需类的层次结构的一部分,它们可以从模式匹配中排除,特别是当您根据密封的层次结构进行穷尽匹配时。当你想要建模正交行为时,这很方便,比如:
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
其他回答
另一个区别是自类型可以指定非类类型。例如
trait Foo{
this: { def close:Unit} =>
...
}
这里的self类型是一个结构类型。其效果是说,任何在Foo中混合的东西都必须实现一个无参数的“close”方法返回单元。这为duck类型提供了安全的mixin。
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
}
另一件没有提到的事情是:因为自类型不是所需类的层次结构的一部分,它们可以从模式匹配中排除,特别是当您根据密封的层次结构进行穷尽匹配时。当你想要建模正交行为时,这很方便,比如:
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
更新:一个主要的区别是自我类型可以依赖于多个类(我承认这有点极端)。例如,你可以有
class Person {
//...
def name: String = "...";
}
class Expense {
def cost: Int = 123;
}
trait Employee {
this: Person with Expense =>
// ...
def roomNo: Int;
def officeLabel: String = name + "/" + roomNo;
}
这允许将Employee mixin添加到Person和Expense的子类中。当然,只有当费用扩展了人员,或者反之,这才有意义。关键是使用自类型Employee可以独立于它所依赖的类的层次结构。它不关心什么扩展什么-如果你切换了费用和人员的层次结构,你不需要修改雇员。
Martin Odersky最初的Scala论文《可伸缩组件抽象》中的2.3节“自类型注释”实际上很好地解释了自类型在mixin组合之外的用途:提供了一种将类与抽象类型关联起来的替代方法。
文中给出的例子如下所示,它似乎没有一个优雅的子类对应:
abstract class Graph {
type Node <: BaseNode;
class BaseNode {
self: Node =>
def connectWith(n: Node): Edge =
new Edge(self, n);
}
class Edge(from: Node, to: Node) {
def source() = from;
def target() = to;
}
}
class LabeledGraph extends Graph {
class Node(label: String) extends BaseNode {
def getLabel: String = label;
def self: Node = this;
}
}