单例类型和 ETSR 不能解决问题。我自己也在 Scala 中寻找相同的功能,但显然它缺少所谓的自类型注释。
在某些情况下,此类自类型注释可能非常有用。考虑一个例子(改编自Circular type parameters question example):
// we want a container that can store elements
trait Container[E <: Element[E]] {
def elements: Seq[E]
def add(elem: E): Unit
}
// we want elements be aware of their enclosing container
trait Element[E <: Element[E]] {
def container: Container[E]
}
假设您将其放入库中。图书馆使用者应该做到以下几点:
object PersonContainer extends Container[Person] {
// actual implementation is not important
def elements = Nil
def add(p: Person) = {}
}
class Person extends Element[Person] { // {1}
def container = PersonContainer
}
没关系,一切都按预期进行。唯一需要担心的是库使用者应该使用自绑定类型参数(代码中的#1)。但这还不是全部。现在假设您有某种 ActiveRecord 模式,并且您想将方法 save 添加到 Element,它只是委托给它的容器的 add 方法。令人惊讶的是,这并不容易:
trait Element[E <: Element[E]] {
def container: Container[E]
def save() = container.add(this) // won't compile
}
found : Element[E]
required: E
直观地说,我们有几个选择:
- 使
add 方法接受Element[E] 而不是E;
- 将
this 转换为Element[E]。
这些选项都不令人满意,只是因为E 与Element[E] 不一样(实现不强制使用自绑定类型参数)。我认为解决这个问题的唯一方法是在 Scala 中使用 self-type 概念(假设我们使用我们最喜欢的语言):
trait Container[E <: Element] {
def elements: Seq[E]
def add(elem: E): Unit
}
trait Element { // the type parameter would be redundant ...
def save() = container.add(this) // ... and this would be possible, too, ...
def container: Container[this] // ... if only we could do this
}
如果编译器可以将this(或者可能是另一个关键字),当它在方括号内使用时,作为实际实现的类型(即与obj.getClass的结果相同的类型),那么问题会消失。
附:有人可以考虑将这些东西包含在 Scala 愿望清单中吗?不幸的是,我不知道实现这样的逻辑有多难,因为臭名昭著的 JVM 擦除可能会出现问题。
附言或者也许还有其他我不知道的 Scala 方式?