kotlin學習(八)

泛型

和Java不同,kotlin要求類型實參要麼被顯式的說明,要麼能夠被編譯器推導出來
一.泛型類型參數

fun <T> List<T>.slice(indices : IntRange) : List<T>{
    //some code
}

可以使用同樣的語法聲明泛型類的拓展屬性上,但是普通屬性是不能聲明的。

val <T> List<T>.p : T
	get() = this.get[size - 2]
val <T> x : T = some()//錯誤

類型參數約束可以限制作爲泛型類和泛型函數的類型實參的類型。
如果把一個類型指定爲泛型類型形參的上界約束,在泛型類型具體的初始化中,其對應的類型實參就必須是這個具體類型或者它的子類型。

fun <T : Number> List<T>.sum() : T//類比於Java中T extends Number

當一個參數需要有多個約束時,其語法稍微有些不同

fun <T> getTwoGeneric(t : T) where T : CharSequence, T : Appendable{
    if (!t.endsWith('.'))
        t.append('.')
}//通過where關鍵字

類比於Java中默認上界Object,沒有指定上界的類型形參將會使用Any?這個默認的上界

二.運行時泛型:擦除和實化類型參數
內聯函數的類型形參能夠被實化,意味着可以在運行時引用實際的類型實參。
通過inline關鍵字並且用reified標記類型參數來實現實化參數。

inline fun <reified T> isA(t : Any) = t is T

編譯器把實現內聯函數的字節碼插入到每一次調用發生的地方。每次你調用帶實化參數類型的函數時,編譯器都知道這次特定調用中用作類型實參的確切類型。因此,編譯器可以生成引用作爲類型實參的具體類的字節碼。
<注>帶reified類型參數的inline函數無法在Java中調用

三.變型:泛型和子類型化
子類型:任何時候如果需要的是類型A的值,你都能夠使用B類型的值當做A,那麼B就稱爲A的子類型。
超類型:如果B是A的子類型,那麼A就是B的超類型。
只有值的類型是變量類型的子類型時,才允許變量存儲該值。
一個非空類型是它的可空版本的子類型麼,但是它們都對應同一個類。

協變:假設存在一個泛型類Producer,如果A是B的子類型,那麼Producer< A>就是Producer< B>的子類型,子類型化被保留了。

interface Producer<out T>{
	fun produce() : T
}

將一個類的類型參數標記爲協變的,在該類型實參沒有精確匹配到函數中定義的類型形參時,可以讓該類的值作爲這些函數的實參傳遞,也可以作爲這些函數的返回值。
對於類型參數,如果把T當做返回值,則其在out位置;如果把T作爲函數參數類型,則其在in位置。
類的參數類型前面的out關鍵字要求所有使用T的方法只能把T放在out位置而不能放在in位置。

class Group<out T : People>{
	val size : Int get() = ..
	operator fun get(i : Int) : T {...}//只在返回值使用到了T,因此是協變的
}

編譯器強制實施了這種限制。
in/out規則只針對類外部可見,即除了private以外。私有方法的參數既不在in位置上也不在out位置上。

逆變:它的子類型化關係與用於類型實參的類的子類型化關係是相反的。

interface Comparator<in T>{
	fun compare(e1 : T, e2 : T) : Int{...}
}

如果B是A的子類型,那麼Comparator< A>就是Comparator< B>的子類型。
in關鍵字的意思是,對應類型的值是傳遞進來給這個類方法的,並且被這些方法消費。和協變的情況類似,約束類型參數的使用將導致特定的子類型化關係。

當函數的實現調用了那些類型參數只出現在out或者in位置的方法時,可以在函數定義中給特定用途的類型參數加上變量修飾符

fun <T> copyList(source : MutableList<out T>, des : MutableList<T>){...}//source無法調用在in位置使用T參數的方法!
當然,可以直接使用List參數(因爲Kotlin中的List只提供get類方法)

這一切被稱爲類型投影。
kotlin中的 MutableList< out T>就對應Java中的MutableList< ? extends T>
kotlin中的 MutableList< in T>就對應Java中的MutableList< ? super T>

星號投影,用來表明不知道關於泛型實參的任何信息。
< Any?>表明的是包含任意的元素,< *>表明的是包含某種特定類型元素的列表,只是不知道具體類型。
該語法對應Java中的?通配符。
當類型參數信息不重要時,可以使用星號投影的語法:不需要任何在簽名中引用類型參數的方法,或者只是讀取數據而不關心它的具體類型。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章