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)
它失败,因为没有方法isValid上Set[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,而不是Nothing和S作为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也没有在这里推断出来.任何提示?
这实际上是 Scala 类型推断的一个众所周知的问题:它无法推断SES“first”并用它来推断E和S。我想到了一个解决方案:
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而不是构造函数参数,它会变得不那么难看,但在您不需要专门化的情况下需要进行一些权衡。我认为应该有一个更好的,但这应该可行。
| 归档时间: |
|
| 查看次数: |
170 次 |
| 最近记录: |