做者 / David Winer, Kotlin 產品經理html
有時候一些可讀性差、不夠明確或者名字太長的類型聲明會干擾代碼的 "自我表達"。這種狀況下,可使用 Kotlin 特別針對這個問題提供的特性: Typealias (本文下稱 "類型別名")。類型別名可使您在不增長新類型的狀況下,爲現有類或函數類型提供替代名稱。android
使用類型別名爲函數類型命名:安全
typealias TeardownLogic = () -> Unit
fun onCancel(teardown : TeardownLogic){ }
private typealias OnDoggoClick = (dog: Pet.GoodDoggo) -> Unit
val onClick: OnDoggoClick
複製代碼
不過要注意這種用法會隱藏傳入參數,使可讀性變差:bash
typealias TeardownLogic = () -> Unit
typealias TeardownLogic = (exception: Exception) -> Unit
fun onCancel(teardown : TeardownLogic){
// 沒法輕易知曉能夠從 TeardownLogic 獲得什麼信息
}
複製代碼
類型別名有助於縮短較長的泛型類名:app
typealias Doggos = List<Pet.GoodDoggo>
fun train(dogs: Doggos){ ... }
複製代碼
使用類型別名時,須要思考是否有必要這麼作: 在這裏使用類型別名真的會讓您的代碼意義更明確、可讀性更好嗎?函數
思考一下,使用類型別名是否使您的代碼變得更易懂spa
若是您正使用的某個類名稱很長,您可使用類型別名來縮短它:3d
typealias AVD = AnimatedVectorDrawable
複製代碼
在此示例中,使用導入別名 (import alias) 會更加合適:code
import android.graphics.drawable.AnimatedVectorDrawable as AVD
複製代碼
更適用的場景是: 若是在代碼中出現了來自不一樣包的相同類名,可使用導入別名來消除這樣的歧義:orm
import io.plaidapp.R as appR
import io.plaidapp.about.R
複製代碼
因爲類型別名須要在類的外部聲明,因此使用時您須要考慮約束它們的可見性。
在使用 Kotlin 開發多平臺工程時,您能夠在公共代碼 (common code) 中寫一個接口,並在相應的平臺代碼中實現這個接口。Kotlin 提供了 "實際聲明" (actual declarations) 和 "預期聲明" (expected declarations) 的機制來簡化這種操做。在公共代碼中聲明的接口爲預期聲明,使用 expect 關鍵字;在相應的平臺代碼中的擴展爲實際聲明,使用 actual 關鍵字。若是平臺代碼中已經實現了公共代碼中的某個接口,而且全部指望方法的簽名一致時,您可使用類型別名將實際聲明的類型名稱映射到指望類型上:
expect annotation class Test
actual typealias Test = org.junit.Test
複製代碼
類型別名不會引入新的類型。例如,反編譯 train 和 play 方法後,能夠看到傳入參數僅使用了 List 類型:
// Kotlin
typealias Doggos = List<Pet.GoodDoggo>
fun train(dogs: Doggos) { ... }
fun play(dogs: Doggos) { ... }
// 反編譯後 Java 代碼
public static final void train(@NotNull List dogs) { … }
public static final void play(@NotNull List dogs) { … }
複製代碼
類型別名不會引入新的類型
所以,您不該該依賴類型別名作編譯類型檢查,而應該使用一個不一樣的類型或者內聯類。例如,下面的方法中,須要傳入一個長整型參數:
fun play(dogId: Long)
複製代碼
爲長整型取一個別名,並不能防止您傳入一個錯的 id:
typealias DogId = Long
fun pet(dogId: DogId) { … }
fun usage() {
val cat = Cat(1L)
pet(cat.catId) // compiles
}
複製代碼
類型別名爲現有類型提供一個更短或更具意義的名稱。但若是您要追求更高的安全性,則建立一個新的類型會比較合適。