型態參數基礎


考慮你要製作一個節點物件,節點可內含的物件可以參數化(就如同List、Set等可進行型態參數化),你可以如下進行定義:
class Node[T] {
var next: Node[T] = _
private[this] var v: T = _
def value: T = v
def value_=(v: T) { this.v = v }
}

你使用[]括住一個代表型態的名稱,之後就可以先使用該名稱來宣告變數,名稱所代表的型態是未定的,你要在建立物件時指定型態,例如指定型態為String:
val first = new Node[String]
first.value = "Justin"
first.next = new Node[String]
first.next.value = "momor"

在上例中,將Node定義中的T參數化為String,所以value傳回String,而value_()方法可以接受String,v的型態也是String。你也可以指定別的型態:
val first = new Node[Int]
first.value = 100
first.next = new Node[Int]
first.next.value = 200

在上例中,將Node定義中的T參數化為Int,所以value傳回Int,而value_()方法可以接受Int,v的型態也是Int。型態參數也可以用在函式定義上,例如在 多維矩陣轉一維矩陣 的例子中,若想讓函式更一般化,則可以如下撰寫:
def toOneByRow[T](array: Array[Array[T]]): Array[T] = {
val arr = new Array[T](array.length * array(0).length)
for(row <- 0 until array.length; column <- 0 until array(0).length) {
arr(row * array(0).length + column) = array(row)(column)
}
arr
}

val arr1 = Array(
Array(1, 2, 3),
Array(4, 5, 6)
)

toOneByRow[Int](arr1).foreach(println)

val arr2 = Array(
Array("one" , "two" , "three"),
Array("four", "five" , "six")
)

toOneByRow[String](arr2).foreach(println))

在定義或使用型態參數時,也可以結合類型推斷(Type inference),讓程式撰寫起來比較簡潔一些,例如:
def toOneByRow[T](array: Array[Array[T]]) = {
val arr = new Array[T](array.length * array(0).length)
for(row <- 0 until array.length; column <- 0 until array(0).length) {
arr(row * array(0).length + column) = array(row)(column)
}
arr
}

val arr1 = Array(
Array(1, 2, 3),
Array(4, 5, 6)
)

toOneByRow(arr1).foreach(println) // 因為類型推斷作用,無須寫明型態資訊

型態參數也可以用來宣告 重複參數,例如:
def show[T](values: T*) = {
values.foreach(println)
}

show(1, 2, 3)
show("one", "two", "three", "four", "five")

在定義特徵(Trait)時,也可以宣告型態參數,例如在 作為共用實作的特徵 就看過的 scala.Ordered[A]:
package scala

trait Ordered[A] {
    def compare(that: A): Int
    def <  (that: A): Boolean = (this compare that) <  0
    def >  (that: A): Boolean = (this compare that) >  0
    def <= (that: A): Boolean = (this compare that) <= 0
    def >= (that: A): Boolean = (this compare that) >= 0
    def compareTo(that: A): Int = compare(that)
}

Ordered[A]可以在使用時宣告A的型態,一個在 作為共用實作的特徵 看過的例子如下:
class Ball(val radius: Int) extends Ordered[Ball] {
def volume = 4 * Math.Pi * Math.pow(radius, 3) / 3
def compare(that: Ball) = this.radius - that.radius
override def equals(a: Any) = a match {
case that: Ball => this.radius == that.radius;
case _ => false
}
override def hashCode = 41 * radius
}

val b1 = new Ball(10)
val b2 = new Ball(20)
println(b1 > b2) // false
println(b1 >= b2) // false
println(b1 < b2) // true
println(b1 <= b2) // true
println(b1 == b2) // false