【问题标题】:Inheriting traits that keep types继承保持类型的特征
【发布时间】:2011-12-10 01:38:19
【问题描述】:

我对 Scala 还很陌生,仍然对其复杂的类型系统感到困惑。

我尝试解决以下问题。我想设计作为可变双向链表成员的类(以及更复杂的数据结构,如堆)。当然,我的目标是能够在恒定时间内从数据结构中删除对象。

我设计了以下特征:

trait DLLMember {
  var next: DLLMember = this
  var prev: DLLMember = this

  ...
}

还有一些用于在列表中添加和删除对象的额外方法。

问题是,当我在实际课堂上时,说:

class IntInDL(val v: Int) extends DLLMember

在解析我的列表时,IntInDL.next 会返回一个 DLLMember 类型而不是 IntInDL,我必须对其进行强制转换才能检索值:这不好......

有没有办法利用 Scala 的类型系统来保证我的工作类型安全?

【问题讨论】:

    标签: scala


    【解决方案1】:

    这是一个小环岛,但以下应该可行:

    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
    

    本质上,这里发生的事情是你用self : T =&gt; 说类型参数T 必须是应用此特征的类的超类。当您在IntInDL 中使用特征时,现在知道nextprev 变量必须是IntInDL 的某个子类型,因为您将其作为类型参数提供。因此,您可以直接使用他们的成员,而无需强制转换。

    如果您提供了一些不属于层次结构的其他任意类型,例如class IntInDL(val v: Int) extends DLLMember[String],它就会编译失败。

    【讨论】:

    • 它工作得很好,但是你如何允许空值到下一个和上一个? (除了将其包装在 Options 中?)
    • @scand1sk 您必须在类型参数上添加一个额外的绑定,我已经编辑了答案以包含它。即便如此,选项也是一个不错的选择。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-06-02
    • 2020-11-11
    • 1970-01-01
    • 2011-01-14
    • 1970-01-01
    相关资源
    最近更新 更多