Scala中的通用继承

alf*_*alf 8 generics scala type-inference

我正在尝试从Scala中的Okasaki的书中实现一些结构,并且在测试中尝试将实际测试保留在基类中,仅使用子类来提供测试中的实例.

例如,对不平衡(树)集的测试如下所示:

class UnbalancedSetSpec
  extends SetSpec(new UnbalancedSet[Int])
  with IntElements
Run Code Online (Sandbox Code Playgroud)

哪里

abstract class SetSpec[E, S](val set: Set[E, S]) extends Specification with ScalaCheck {

  implicit def elements: Arbitrary[E]

  // ...

  private def setFrom(es: Seq[E]): S = es.foldRight(set.empty)(set.insert)
}
Run Code Online (Sandbox Code Playgroud)

现在有时我想专门研究儿童规范,例如

class RedBlackSetSpec
  extends SetSpec(new RedBlackSet[Int])
  with IntElements {

  "fromOrdList" should {
    "be balanced" ! prop { (a: List[Int]) =>
      val s = RedBlackSet.fromOrdList(a.sorted)

      set.isValid(s) should beTrue
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

它失败,因为没有方法isValidSet[E, S]-它的定义RedBlackSet[E].但是,如果我继续前进,改变SetSpec[E, S](val set: Set[E, S])SetSpec[E, S, SES <: Set[E, S]](val set: SES),这种特殊的问题就消失了,但代码仍然无法编译:

Error:(7, 11) inferred type arguments [Nothing,Nothing,okasaki.RedBlackSet[Int]] do not conform to class SetSpec's type parameter bounds [E,S,SES <: okasaki.Set[E,S]]
  extends SetSpec(new RedBlackSet[Int])
          ^

Error:(7, 11) inferred type arguments [Nothing,Nothing,okasaki.UnbalancedSet[Int]] do not conform to class SetSpec's type parameter bounds [E,S,SES <: okasaki.Set[E,S]]
  extends SetSpec(new UnbalancedSet[Int])
          ^
Run Code Online (Sandbox Code Playgroud)

定义RedBlackSet如下:

package okasaki

class RedBlackSet[E](implicit ord: Ordering[E]) extends Set[E, RBTree[E]] {
Run Code Online (Sandbox Code Playgroud)

所以我希望E可以推断为Int,而不是NothingS作为RBTree[Int]-但它不会发生.

class RedBlackSetSpec
  extends SetSpec[Int, RedBlackSet.RBTree[Int], RedBlackSet[Int]](new RedBlackSet[Int])
  with IntElements {
Run Code Online (Sandbox Code Playgroud)

class UnbalancedSetSpec
  extends SetSpec[Int, BinaryTree[Int], UnbalancedSet[Int]](new UnbalancedSet[Int])
  with IntElements
Run Code Online (Sandbox Code Playgroud)

工作得很好,但看起来很难看.

我很难理解为什么E,S也没有在这里推断出来.任何提示?

Ale*_*nov 1

这实际上是 Scala 类型推断的一个众所周知的问题:它无法推断SES“first”并用它来推断ES。我想到了一个解决方案:

class RedBlackSetSpec(override val set: RedBlackSet[Int]) extends SetSpec(set) with IntElements {
  def this() = this(new RedBlackSet[Int])
  ...
}
Run Code Online (Sandbox Code Playgroud)

set如果您使用SetSpec抽象val而不是构造函数参数,它会变得不那么难看,但在您不需要专门化的情况下需要进行一些权衡。我认为应该有一个更好的,但这应该可行。