泛型二叉搜索树
通过参数化型别,我们可以将先前的 IntSet 以泛型风格重写
1: // from IntSet to Set
2: abstract class Set[A] {
3: def incl(x: A): Set[A]
4: def contains(x: A): Boolean
5: }
6: // ... But
非常直接了当的做法。类似的代码在 Groovy 中将能够顺利编译并(多数情况下)正确运行,但是在 Scala 中,我们将遇到小小的问题:在 IntSet 中,我们在 incl 和 contains 方法中均调用了 Int 的 > 和 < 方法,但当使用泛型的时候,我们无法保证 A 具有这两个方法。为此,我们必须对 A 进行小小的修饰:要求 A 必须已混入了 trait Ordered。
1: // The parameter declaration A <: Ordered[A] introduces A as a type
2: // parameter which must be a subtype of Ordered[A], i.e. its values must be
3: // comparable to values of the same type.
4: trait Set[A <: Ordered[A]] {
5: def incl(x: A): Set[A]
6: def contains(x: A): Boolean
7: }
8:
9: class EmptySet[A <: Ordered[A]] extends Set[A] {
10: def contains(x: A) = false
11: def incl(x: A): Set[A] =
12: new NonEmptySet(x, new EmptySet[A], new EmptySet[A])
13: }
14:
15: class NonEmptySet[A <: Ordered[A]](elem: A, left: Set[A], right: Set[A])
16: extends Set[A] {
17: def contains(x: A): Boolean =
18: if(x < elem) left contains x
19: else if(x > elem) right contains x
20: else true
21: def incl(x: A): Set[A] =
22: if(x < elem) new NonEmptySet(elem, left incl x, right)
23: else if(x > elem) new NonEmptySet(elem, left, right incl x)
24: else this
25: }
26:
27: case class Num(value: Double) extends Ordered[Num] {
28: def compare(that: Num): Int =
29: if(this.value < that.value) -1
30: else if(this.value > that.value) 1
31: else 0
32: }
33:
34: val s = new EmptySet[Num].incl(Num(1.0)).incl(Num(2.0))
35: println(s.contains(Num(1.5)))
36: // Int does not conform to type parameter bound Ordered[Int]
37: // val w = new EmptySet[Int] // Error!
协变 & 逆变
1: class Stack[+A] {
2: def push[B >: A](x: B): Stack[B] = new NonEmptyStack(x, this)
3: }
通过指定 A 是 B 的子类强迫 push 接收 A 或其基类型。不仅如此,其返回值也会根据 B 的类型自动做相应的改变!(说实话,除了这个自动改变返回值类型的特点外,我一点也无法领会 Scala 在类型处理上的美妙之处,作为强测试的拥护者,我真的真的不在意强类型,but,目前我还没有学完,不是吗?)
Nothing
1: abstract class Stack[+A] {
2: def push[B >: A](x: B): Stack[B] = new NonEmptyStack(x, this)
3: def isEmpty: Boolean
4: def top: A
5: def pop: Stack[A]
6: }
7:
8: object EmptyStack extends Stack[Nothing] {
9: def isEmpty = true
10: def top = error("EmptyStack.top")
11: def pop = error("EmptyStack.pop")
12: }
13:
14: class NonEmptyStack[+A](elem: A, rest: Stack[A]) extends Stack[A] {
15: def isEmpty = false
16: def top = elem
17: def pop = rest
18: }