看一下以下代码片段:
trait T { def y = println("hello") }
class A {
self: T =>
def x = y
}
abstract class B {
val self: T
def x = self.y
}
val a = new A with T
val b = new B with T {
val self = this
}
a.x
b.x
A类和B类具有特征T的引用,A具有自引用和B 正在使用作文。
我在这里只看到两个不同之处:第一个是创建新对象 和第二个访问T.
在B中有更多的语法糖,我不需要显式访问 引用self,我不需要绑定变量。
是否存在其他差异,是否存在某种情况 应该优先而不是其他?
答案 0 :(得分:1)
在scala中,当我必须在另一个类中“混合”一个类时,我才使用合成。在你的例子中, 如果T是一个班级:
class T { def y = println("hello") }
然后new X with T
将不可能。
答案 1 :(得分:1)
你的问题似乎不包括普通继承。对于A
,与class A extends T
相比,自我类型没有优势。对于B
,如果您打算仅使用self = this
创建它,则扩展也同样好(并且更简单)
我认为自我类型的用例并不多(但这不是对组合与继承的讨论)
其中之一是强制将特征仅作为另一种尚未知的类型的子类型进行实例化,因为它显示为类型参数或抽象类型成员。例如,trait X[A] {self: A => ...}
您可以使用类型成员查看scala网站上的this realistic example。
另一个是当你编写模块而不是实例时,特别是当模块具有类型成员时,使组合仅在编译时可行。这或多或少与CakePattern有关。
组合(无论是使用抽象val还是构造函数参数)当然具有强大的优势,您可以传递T的外部实例,在B的不同实例之间共享它,更加动态地选择它。实例可以传递给函数并从函数返回,mixins不能