我对Scala很新,并且仍然对其复杂的类型系统感到困惑.
我尝试解决以下问题.我想设计属于可变双向链表(以及更复杂的数据结构,如堆)的成员的类.当然,我的目标是能够在恒定的时间内从数据结构中删除对象.
我设计了以下特征:
trait DLLMember {
var next: DLLMember = this
var prev: DLLMember = this
...
}
Run Code Online (Sandbox Code Playgroud)
使用一些其他方法从列表中添加和删除对象.
问题是,当我在实际上课时,说:
class IntInDL(val v: Int) extends DLLMember
Run Code Online (Sandbox Code Playgroud)
在解析我的列表时,IntInDL.next会返回一个DLLMember类型而不是IntInDL,我必须强制转换它来检索值:这不好...
有没有办法利用Scala的类型系统来保持我的工作类型安全?
这是一个小迂回,但以下应该工作:
trait DLLMember[T >: Null <: DLLMember[T]] { self : T =>
var next: T = this
var prev: T = this
...
}
class IntInDL(val v: Int) extends DLLMember[IntInDL]
var i = new IntInDL(3)
println(i.next.v) //prints 3
i.next = null //is valid
i.next = new IntInDL(1) //is valid
Run Code Online (Sandbox Code Playgroud)
从本质上讲,这里发生的是你所说self : T =>的类型参数T必须是应用此特征的类的超类.当你使用trait时IntInDL,现在已知next和prev变量必须是某个子类型,IntInDL因为你提供了它作为type参数.因此,您可以直接使用其成员,而无需进行强制转换.
例如,如果您提供了一些不属于层次结构的其他任意类型class IntInDL(val v: Int) extends DLLMember[String],那么它将无法编译.