scala當中的類型參數


類型參數主要就是研究scala當中的類或者scala當中的方法的泛型

1、scala當中的類的泛型

        object Demo8 {

         def main(args: Array[String]): Unit = {

         val result1 = new MyClass("hello",50)

         val result2 = new MyClass[Any,Any]("zhangsan","Lisi");

         }

        }

          

        /**

         * 定義一個class類,接收兩個參數,但是兩個參數都是泛型,泛型的類型,會根據我們

         * 創建類的實例化對象的時候,動態的傳遞進行動態的推斷

         * @param first

         * @param second

         * @tparam T

         * @tparam B

         */

        class MyClass[T,B](first:T,second:B){

         println(first+","+second)

   

}

2、函數的泛型

我們的函數或者方法,也可以有類型參數

        object methodType{

         def getMiddle[T](canshu:T) ={

         canshu

         }

         def main(args: Array[String]): Unit = {

         // 從參數類型來推斷類型

         println(getMiddle(Array("Bob", "had", "a", "little", "brother")).getClass.getTypeName)

         //指定類型,並保存為具體的函數。

         val f = getMiddle[String] _

         println(f("Bob"))

         }

3、scala當中的上下界之泛型類型的限定

在scala當中,我們可以通過上界或者下界來限定我們泛型的類型,類似於java當中的

? extends T ?號就表示我們使用的泛型,必須是T類型的子類,這種情況叫做上界

? super T ?號就表示我們使用的泛型,必須是T類型的父類,這種情況叫做下界

在scala當中上界的表示方法使用的是 "<:", 這個符號就是表示上界,這種形式稱之為泛型的上界

在scala當中下界的表示方式使用的是 ">:", 這個符號就是表示下界,這種形式稱之為泛型的下界

   

3.1、泛型的上界限定

我們可以通過上界的限定,限定我們傳入的類型必須是某個類型的子類

   

        class Pair1[T <: Comparable[T]](val first: T, val second: T) {

         def smaller = if (first.compareTo(second) < 0) first else second

        }

          

        object Main1 extends App{

         override def main(args: Array[String]): Unit = {

         val p = new Pair1("hello", "Brooks")

         println(p.smaller)

         }

        }

   

 3.2、泛型的下界限定

我們可以通過下界的限定,限定我們傳入的類型必須是某個類型的父類

   

        class Pair2[T](val first: T, val second: T) {

         def replaceFirst[R >: T](newFirst: R) = new Pair2[R](newFirst, second)

         override def toString = "(" + first + "," + second + ")"

        }

          

        object Main2 extends App{

         override def main(args: Array[String]): Unit = {

         val p = new Pair2("Nick", "Alice")

         println(p)

         println(p.replaceFirst("Joke"))

         println(p)

         }

        }

   

在Java中,T同時是A和B的子類型,稱之為多界,形式如:<T extends A & B>。

在Scala中,對上界和下界不能有多個,但是可以使用混合類型,如:[T <: A with B]。

在Java中,不支持下界的多界形式。如:<T super A & B>這是不支持的。

在Scala中,對復合類型依然可以使用下界,如:[T >: A with B]。

   

   

4、scala當中的視圖界定

說白了就是將我們的泛型轉化成了具體的類型

在Scala中,如果你想標記某一個泛型可以隱式的轉換為另一個泛型,可以使用:[T <% Comparable[T]],由於Scala的Int類型沒有實現Comparable接口,所以我們需要將Int類型隱式的轉換為RichInt類型,比如:

我們如果需要比較兩個值的大小,那么我們的兩個值必須是Comparable的子類,那么我們可以使用泛型 T <% Comparable 來限制我們泛型必須是Comparable的子類,並且我們的泛型在執行真正比較的方法的時候,會根據我們傳入的類型,自動推斷,進行隱式的轉換,例如我們傳入4,2 進行比較,那么我們會將4, 2 這兩個類型做自動推斷,轉換成真正的RichInt類型然后再繼續進行比較

   

/**

* 使用 <% 來實現我們類型的隱式轉換

* @param first

* @param second

* @tparam T

*/

class Pair3[T <% Comparable[T]](val first: T, val second: T) {

def smaller = if (first.compareTo(second) < 0) first else second

override def toString = "(" + first + "," + second + ")"

}

   

object Main3 extends App {

val p = new Pair3(4, 2)

println(p.smaller)

}

   

5、scala當中的協變,逆變和非變

協變和逆變主要是用來解決參數化類型的泛化問題。Scala的協變與逆變是非常有特色的,完全解決了Java中泛型的一大缺憾;舉例來說,Java中,如果有 A是 B的子類,但 Card[A] 卻不是 Card[B] 的子類;而 Scala 中,只要靈活使用協變與逆變,就可以解決此類 Java 泛型問題;

由於參數化類型的參數(參數類型)是可變的,當兩個參數化類型的參數是繼承關系(可泛化),那被參數化的類型是否也可以泛化呢?Java中這種情況下是不可泛化的,然而Scala提供了三個選擇,即協變("+")、逆變("-")和非變。

下面說一下三種情況的含義,首先假設有參數化特征Queue,那它可以有如下三種定義。

  1. trait Queue[T] {}

    這是非變情況。這種情況下,當類型B是類型A的子類型,則Queue[B]與Queue[A]沒有任何從屬關系,這種情況是和Java一樣的。

  2. trait Queue[+T] {} 
    這是協變情況。這種情況下,當類型B是類型A的子類型,則Queue[B]也可以認為是Queue[A]的子類型,即Queue[B]可以泛化為Queue[A]。也就是被參數化類型的泛化方向與參數類型的方向是一致的,所以稱為協變。
  3.   trait Queue[-T] {} 

    這是逆變情況。這種情況下,當類型B是類型A的子類型,則Queue[A]反過來可以認為是Queue[B]的子類型。也就是被參數化類型的泛化方向與參數類型的方向是相反的,所以稱為逆變。 

協變、逆變、非變總結

  • C[+T]:如果A是B的子類,那么C[A]是C[B]的子類。
  • C[-T]:如果A是B的子類,那么C[B]是C[A]的子類。
  • C[T]: 無論A和B是什么關系,C[A]和C[B]沒有從屬關系。

   

案例

package com.starzy.scala

   

class Super

class Sub extends Super

//協變

class Temp1[+A](title: String)

//逆變

class Temp2[-A](title: String)

//非變

class Temp3[A](title: String)

   

object Covariance_demo{

def main(args: Array[String]) {

//支持協變 Temp1[Sub]還是Temp1[Super]的子類

val t1: Temp1[Super] = new Temp1[Sub]("hello scala!!!")

//支持逆變 Temp1[Super]Temp1[Sub]的子類

val t2: Temp2[Sub] = new Temp2[Super]("hello scala!!!")

//支持非變 Temp3[Super]Temp3[Sub]沒有從屬關系,如下代碼會報錯

//val t3: Temp3[Sub] = new Temp3[Super]("hello scala!!!")

//val t4: Temp3[Super] = new Temp3[Sub]("hello scala!!!")

println(t1.toString)

println(t2.toString)

}

}

   


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM