翻譯說明:java
原標題: When (and when not) to Use Type Parameter Constraints in Kotlinapp
原文地址: typealias.com/guides/when…dom
原文做者: Dave Leedside
翻譯系列:函數
原創系列:post
實戰系列:ui
今天這篇文章依舊很簡單,只要搞懂一個東西就能夠了。那就是泛型中的類型形參的約束,這個概念在Java中也有的。可是咱們有個疑惑是什麼狀況下使用泛型類型形參呢?spa
當你在聲明一個泛型時,Kotlin容許你給這個泛型的類型形參增長約束條件,換言之就是把類型形參可接受的類型實參限制在一個類型範圍內。那這個有什麼做用呢?讓咱們一塊兒來看下面這個例子:插件
想像下有這麼個需求場景: 假設你家裏有幾隻寵物,你想選擇一個最喜歡的:翻譯
fun <T> chooseFavorite(pets: List<T>): T {
val favorite = pets[random.nextInt(pets.size)]
// This next line won't compile - because `name` can't be resolved
println("My favorite pet is ${favorite.name}")
return favorite
}
複製代碼
println()
函數聲明不會經過編譯,由於你沒法經過T
來引用name
屬性。由於T
能夠是調用者指定的任何內容。例如,像如下代碼實現,T
就是一個Int類型,很明顯它就沒有name屬性:
chooseFavorite(listOf(1, 2, 3))
複製代碼
你能夠嘗試改造一下這個函數,把泛型去掉:
fun chooseFavorite(pets: List<Pet>): Pet {
val favorite = pets[random.nextInt(pets.size)]
println("My favorite pet is ${favorite.name}")
return favorite
}
複製代碼
這個處理看起來貌似沒有什麼問題,可是咱們會遇到一種不想要的返回值類型。如下是咱們調用該函數時會發生的狀況:
val pets: List<Dog> = listOf(Dog("Rover"), Dog("Sheba"))
val favorite: Pet = chooseFavorite(pets)
複製代碼
儘管咱們聲明定義的是List< Dog >,可是經過chooseFavorite返回的是一個Pet類型,除非這裏咱們使用強制類型轉換。
咱們能夠經過指定上限來限制類型形參-換句話說就是指定你想要接收的超類型。在咱們的例子中,咱們但願此函數做爲List <Pet>
處理List <Dog>
,List <Cat>
也就是既包含Cat
類型也包含Dog
類型的混合Pet
類型的列表中。
fun <T : Pet> chooseFavorite(pets: List<T>): T {
val favorite = pets[random.nextInt(pets.size)]
println("My favorite pet is ${favorite.name}")
return favorite
}
複製代碼
這裏的類型形參的聲明是<T:Pet>
,這個Pet
就是上界約束。如今咱們已經指定了這個,調用代碼只能傳遞Pet類型以及它的子類型。
val pets: List<Dog> = listOf(Dog("Rover"), Dog("Sheba"))
val favorite: Dog = chooseFavorite(pets)
複製代碼
下面兩種是你須要使用類型形參約束狀況:
這是一個快速的「備忘單」表,可幫助您決定哪一種狀況使用什麼?
須要調用成員(類的成員函數或屬性) | 不須要調用成員(類的成員函數或屬性) | |
---|---|---|
須要保留類型 | 使用帶有類型參數約束的泛型 | 使用不帶類型參數約束的泛型 |
不須要保留類型 | 使用非泛型和適當的抽象 | 使用Java中的原生態類型 |
約束還有不少 - 您能夠指定多個參數的約束,以及對同一參數的多個約束。對於全部細節,請查看概念文章Type Parameter Constraint。您還能夠在Kotlin的官方參考文檔中快速查看經常使用約束。
本篇文章核心點在於什麼狀況下該使用泛型約束,做者總結的很好就是那種表格,理解和掌握了那張表格,那麼你在使用泛型形參約束上就會成竹在胸。關於那個表格可能有點難理解,我這裏再補充解釋一下:
List<Dog>
,可是chooseFavorite方法返回依然是父類Pet,外部接收類型Dog因此避免不了強制類型轉換。總之一句話: 是否須要保留類型,也就直接決定了是否使用泛型,若是不保留類型的話能夠不使用泛型,函數外部接收者可使用抽象的父類來接收;若是保留類型,函數外部接收者就必須是明確一個類型,那麼此時若是還用抽象父類就避免不了類型轉換,那麼此時就應該使用泛型一、是否須要調用成員決定了在使用泛型前提下,是否使用泛型類型參數約束;不然直接可使用抽象
二、是否保留類型決定了是否使用泛型
三、既保留類型又調用成員,則就是使用泛型且帶形參約束條件
四、不保留類型又調用成員,則就是不使用泛型和適當的抽象
五、保留類型不調用成員,則就是使用泛型不帶形參約束條件
六、不保留類型不調用成員,則就是使用java中原生態類型,例如Java中的List類型
歡迎關注Kotlin開發者聯盟,這裏有最新Kotlin技術文章,每週會不按期翻譯一篇Kotlin國外技術文章。若是你也喜歡Kotlin,歡迎加入咱們~~~