【问题标题】:Abstract classes/traits and invariant functions抽象类/特征和不变函数
【发布时间】:2010-12-14 11:09:48
【问题描述】:

给定一个特征T

trait T {
  def v: Int
  def +(t: T): T
}

以下类A

case class A(v: Int) extends T {
  def +(a: A) = A(v + a.v)
}

不是T 的有效子类型。 A.+ 的实现过于严格,因为它只接受 A 类型的元素,而 T.+ 的签名要求所有实现都能够接受 T 类型的对象,而不仅仅是 A 类型的对象. 到目前为止,还算合理。

如果我想允许 T 的实现如此严格,我可以修改 TA 的声明,如下所示

trait T[This <: T[This]] {
  def v: Int
  def +(t: This): This
}

case class A(v: Int) extends T[A] {
  def +(a: A) = A(v + a.v)
}

这显然会破坏类型签名。

是否有另一种方式来声明T 的实现只需要与它们自己类型的对象兼容?

第一次编辑回复Landei's answer below

虽然自我类型确实缩短了当前签名,但它们不会缩短出现 T 的其他签名,例如

trait C[D <: T[D], S] { self: S =>
  def +(perm: D): S
  def matches(other: S): Boolean
}

【问题讨论】:

    标签: generics inheritance scala signature variance


    【解决方案1】:

    你可以使用自我类型:

    trait T[S] {
      self:S => 
      def v: Int
      def +(t: S): S
    }
    
    case class A(v: Int) extends T[A] {
      def +(a: A) = A(v + a.v)
    }
    

    【讨论】:

    • 请看我上面的“第一次编辑”。不过谢谢,我之前没有考虑过自类型注释。
    • 我不知道一个通​​用的解决方案。根据您的意图和类层次结构,类型类模式(使用隐式)可能适用(参见 Numeric 示例)。另一种尝试是类型变量(为了将 D 拉到特征“内部”)。
    【解决方案2】:

    您可以使用类型成员来做到这一点。我不知道你到底要找什么牌子的“短”。有一些冗余,但另一方面,没有类型参数可以为您节省大量的括号。

    trait TT {
      type This <: TT
      def v: Int
      def +(t: This): This
    }
    case class AA(v: Int) extends TT {
      type This = AA
      def +(a: This) = AA(v + a.v)
    }
    

    【讨论】:

    • 与我的建议不同的是,您可以将 TT 的任何子类型分配给 This。我认为 mhs 想将 This 限制为类本身的类型。但是,您的方法会如何回答后续问题(具有特征 D)?
    猜你喜欢
    • 1970-01-01
    • 2011-11-19
    • 1970-01-01
    • 2011-01-01
    • 2020-04-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-07-01
    相关资源
    最近更新 更多