Scala 泛型型別和方法

智慧先行者發表於2014-12-21
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)
}

 

相關文章