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) }