scala> val f = getMiddle[Double] _
f: Array[Double]=> Double =<function1>
類型變量界定
有時候對類型變量進行限制,例如定一個上界,也就是父類型
例如下面的例子,對於Pair類,smaller方法獲取較小的值,添加一個上界 T <: Comparable[T],這就意味着T必須是Comparable[T]的子類型,這樣可以實例化Pair[Java.lang.String],但是不能實例化Pair[java.net.URL],Pair[Int]也不能
classPair[T <: Comparable[T]](val first:T,val second:T){
def smaller:T =if(first.compareTo(second)<0) first else second
}//實例化
scala> val a =newPair("a","b")
a: Pair[String]= Pair@5513a46b//錯誤的實例化
scala> val a =newPair(1,2)<console>:12: error: inferred type arguments [Int]do not conform to classPair's type parameter bounds [T <: Comparable[T]]
val a =newPair(1,2)^<console>:12: error: type mismatch;
found :Int(1)
required: T
val a =newPair(1,2)^<console>:12: error: type mismatch;
found :Int(2)
required: T
val a =newPair(1,2)^
def makePair[T](first:T,second:T):Array[T]={
val r =newArray[T](2)r(0)= first
r(1)= second
r
}<console>:12: error: cannot find classtagfor element type T
val r =newArray[T](2)^
還是要使用
import scala.reflect.ClassTag
def makePair[T : ClassTag](first:T, second:T):Array[T]={
val r =newArray[T](2)r(0)= first
r(1)= second
r
}
實驗表明,使用List,Vector,Set等Collection的時候不需要使用ClassTag
多重界定
類型變量同時使用上界和下界,語法爲T >: Lower <: Upper
但不能同時又多個上界或多個下界,不過可以要求一個類型實現多個特質,就像T <: Comparable[T] with Serializable with Cloneable
同時多個上下文界定T : Ordering : ClassTag
類型約束
另一個限定類型的方式,三種關係
T =:= U, T 是否等於U
T <:< U,T是否爲U的子類型
T => U,T能否被轉換爲U
要使用這種約束,需要添加隱式類型證明參數,例如
class Pair3[T] (val first :T , val second : T)(implicit ev:T <:< Comparable[T])
trait Friend[-T]{
def befriend(someone:T)}
def makeFriendWith(s:Student,f:Friend[Student])={f.befriend(s)}classPersonextendsFriend[Person]{
override def befriend(someone: Person): Unit =()}classStudentextendsPerson
val susan =newStudent
val fred =newPersonmakeFriendWith(susan,fred)
abstractclassAnimal{
def name: String
}caseclassCat(name: String)extendsAnimalcaseclassDog(name: String)extendsAnimal
object CovarianceTest extendsApp{
def printAnimalNames(animals: List[Animal]): Unit ={
animals.foreach { animal =>println(animal.name)}}
val cats: List[Cat]=List(Cat("Whiskers"),Cat("Tom"))
val dogs: List[Dog]=List(Dog("Fido"),Dog("Rex"))printAnimalNames(cats)// Whiskers// TomprintAnimalNames(dogs)// Fido// Rex}
逆變
abstractclassAnimal{
def name: String
}caseclassCat(name: String)extendsAnimalcaseclassDog(name: String)extendsAnimalabstractclassPrinter[-A]{
def print(value: A): Unit
}classAnimalPrinterextendsPrinter[Animal]{
def print(animal: Animal): Unit =println("The animal's name is: "+ animal.name)}classCatPrinterextendsPrinter[Cat]{
def print(cat: Cat): Unit =println("The cat's name is: "+ cat.name)}
object testcontra extendsApp{
val myCat: Cat =Cat("Boots")
def printMyCat(printer: Printer[Cat]): Unit ={
printer.print(myCat)}
val catPrinter: Printer[Cat]=newCatPrinter
val animalPrinter: Printer[Animal]=newAnimalPrinterprintMyCat(catPrinter)printMyCat(animalPrinter)}
scala>classPair[+T](var first:T,var second:T)<console>:11: error: covariant type T occurs in contravariant position in type T of value first_=classPair[+T](var first:T,var second:T)^