abstract class Stack[A] { def push(x: A): Stack[A] = new NonEmptyStack[A](x, this) def isEmpty: Boolean def top: A def pop: Stack[A] val contents: T = _ //初始值:_ ,表示一个默认值,数字类型是0 ,boolean是false ,Unit是() (无参数无返回),其他是null } class EmptyStack[A] extends Stack[A] { def isEmpty = true def top = error("EmptyStack.top") def pop = error("EmptyStack.pop") } class NonEmptyStack[A](elem: A, rest: Stack[A]) extends Stack[A] { def isEmpty = false def top = elem def pop = rest } val x = new EmptyStack[Int] val y = x.push(1).push(2) println(y.pop.top) def isPrefix[A](p: Stack[A], s: Stack[A]): Boolean = { p.isEmpty || p.top == s.top && isPrefix[A](p.pop, s.pop) } val s1 = new EmptyStack[String].push("abc") val s2 = new EmptyStack[String].push("abx").push(s1.top) println(isPrefix[String](s1, s2))
类型参数边界
在用类型参数定义了一个抽象类Set[A]后,在实现中要用到比较(<>),但是不能确定A的具体类型,因此不能直接使用。一个解决办法就是对合法类型进行限制,对只含有方法<>的类型放行。在标准库里有一个特质Ordered[A],用来表示可比较的类型。现在可以强制要求这个类型为Ordered的子类型。可以通过给出一个上界(upper bound)的方式来解决这个问题:
abstract class Set[A] { def incl(x: A): Set[A] def contains(x: A): Boolean }
// 传入的A类型参数必须是Ordered[A]的子类型 class EmptySet[A <: Ordered[A]] extends Set[A] { def contains(x: A): Boolean = false def incl(x: A): Set[A] = new NonEmptySet(x, new EmptySet[A], new EmptySet[A]) // 在new NonEmptySet(...)时,没有写入类型参数。因为可以从返回值类型中推断出来。 } class NonEmptySet[A <: Ordered[A]](elem: A, left: Set[A], right: Set[A]) extends Set[A] { def contains(x: A): Boolean = if (x < elem) left contains x else if (x > elem) right contains x else true def incl(x: A): Set[A] = if (x < elem) new NonEmptySet(elem, left incl x, right) else if (x > elem) new NonEmptySet(elem, left, right incl x) else this }
// 先创建一个Ordered的子类 case class Num(value: Double) extends Ordered[Num] { def compare(that: Num): Int = if (this.value < that.value) -1 else if (this.value > that.value) 1 else 0 } val s = new EmptySet[Num].incl(Num(1.0)).incl(Num(2.0)) s.contains(Num(1.5))
变化型注解(variance annotation)
“+”表示协变,“-”表示逆变。
C[+T]:如果A是B的子类,那么C[A]是C[B]的子类。
C[-T]:如果A是B的子类,那么C[B]是C[A]的子类。
C[T]:无论A和B是什么关系,C[A]和C[B]没有从属关系。
协变类型应该出现在协变位置,这些位置包括:类里值的参数类型;方法的返回值类型;以及其他协变类型中的参数。放在其他地方会被拒绝
class Array[+A] { def apply(index: Int): A def update(index: Int, elem: A) // 可以通过下界(lower bounds)来解决这个问题 ^ covariant type parameter A appears in contravariant position. }
// 下界(Lower Bounds) // B是A的父类 class Stack[+A] { def push[B >: A](x: B): Stack[B] = new NonEmptyStack(x, this) }