重學 Kotlin —— typealias ,換了個馬甲,我就不認識你了 ?

這裏是 重學 Kotlin 系列第二篇,本文永久更新地址 :https://xiaozhuanlan.com/topic/0846175293 。java

可能還真的就不認識了。web

今天的主角是 type alias,翻譯過來叫 類型別名。先來看一下文章目錄:編輯器

  1. 什麼是 typealias ?
  2. typealias 的本質
  3. typealias 存在的意義是什麼?
  4. typealias 的使用注意事項

什麼是 typealias ?

這是一個很基礎的關鍵字,但可能不少人沒有使用過。它的做用十分簡單,給已有類型取一個別名,能夠像使用原類型同樣使用這個 「類型別名」函數

舉個簡單的例子:flex

typealias Name = String
val name : Name = "java" println(name.length) 複製代碼

String 取個別名 Name ,在使用過程當中,NameString 是徹底等價的。優化

既然是等價的,使用別名的意義是什麼呢?ui

別急,typealias 不只僅支持給類取別名,它的用法豐富的讓你想象不到。this

// 類和接口
typealias Name = String typealias Data = Serializable  // 函數類型 typealias GetName = () -> String typealias Handler = CoroutineScope.() -> Unit  // 泛型 typealias P<T> = Comparable<T> typealias Pairs<K, V> = HashMap<K, V> typealias Numbers = Array<Number>  // object object Single {} typealias X = Single  class Util {  companion object {  val count = 1  } } typealias Count = Util.Companion  // inner class typealias NotificationBuilder = NotificationCompat.Builder  class Outer { inner class Inner } typealias In = Outer.Inner  // 枚舉 enum class Color { RED, YELLOW, GREEN } typealias color = Color  // 註解 typealias Jvm = JvmStatic 複製代碼

上面的枚舉用法中,須要注意的一點是,只能爲枚舉類 Color 取別名,沒法爲具體的枚舉值取別名 。諸如 typealias Red = Color.RED 是不容許的。url

幾乎沒有 typealias 不適用的類型。說到如今,你又得疑問了,類型別名存在的意義是什麼 ?這樣簡單的取個別名,爲何不直接使用原類型呢 ?spa

typealias 的本質

暫且別急,咱們先來看一下 typealias 的實現原理,說不定能夠有一些發現。

反編譯下面這個簡單的例子:

typealias Binary = ByteArray fun getBinary(string: String) : Binary = string.toByteArray() 複製代碼

查看其 Java 代碼 :

public final class TypealiasKt {
 @NotNull  public static final byte[] getBinary(@NotNull String string) {  Intrinsics.checkParameterIsNotNull(string, "string");  Charset var2 = Charsets.UTF_8;  boolean var3 = false;  byte[] var10000 = string.getBytes(var2);  Intrinsics.checkExpressionValueIsNotNull(var10000, "(this as java.lang.String).getBytes(charset)");  return var10000;  } } 複製代碼

代碼中根本找不到類型別名 Binary 的蹤跡。通過編譯以後,類型別名會被原類型直接替換。這僅僅只是 Kotlin 豐富的語法糖之一,編譯器在其中作了一些手腳。

typealias 存在的意義是什麼 ?

如今,你估計更加困惑了。

開發者手動聲明一個類型別名,編譯器再自動替換回原類型。意義何在?

惟一能想到的一點大概只有 "代碼可讀性" ,這裏的代碼可讀性還要打上了一個大大的引號。

複雜的業務邏輯下,你的代碼中可能會出現超長命名,多參數,多泛型類型的類名,接口名,函數名。

typealias FileTable<K> = MutableMap<K, MutableList<File>>
typealias OnPermissionResult = ActivityCompat.OnRequestPermissionsResultCallback typealias SimpleName = LonglonglonglonglonglonglonglonglonglonglonglonglonglonglongName 複製代碼

用類型別名來代替本來可讀性很差(名字太長或者聲明覆雜)的類型名,這可能就是 typealias 的主要做用。

至於到底有沒有提高可讀性?我以爲這是有代價的。所以而喪失的是直觀的類型聲明。以上面代碼塊中的 FileTable 爲例,一眼看過去,你能發現它是一個 MutableMap<K, MutableList<File>> 嗎?確定不能。特別在團隊開發中,除了這個代碼的貢獻者,可能每一位都要到類型別名聲明處進行查看。

有人可能也會有不同的聲音。統一的全局聲明很正常,並且也方便作統一修改,避免到代碼使用處一一修改。何況 IDE 都會自動提示類型別名的聲明。沒有不使用 typealias 的道理。

因此,這是一個仁者見仁,智者見智的問題。你以爲有用就可使用,任何一門技術確定都有它的使用場景,並無必要去過多爭論。

我用協程仍是用 RxJava? 我用 LiveData 仍是用事件總線? 我用 ViewBinding 仍是 DataBinding ? ......

這幾個問題可能比較常見,可是上面的每一組選擇,若是你真正深刻了解其技術本質的話,就會發現它們的使用場景並不同,也就不會存在 如何選擇 的疑問了。

typealias 使用注意事項

有點跑偏了,再回到 typealias 。後面再說一些 typealias 的注意事項,內容會比較零散,後續也可能繼續增長。

typealias 能夠寫在哪裏?

只能聲明在文件頂層位置,其餘任何地方都不行。

與 Java 如何交互?

拒絕和 Java 進行交互。

禁止套娃!

首先咱們是能夠 給別名取別名 的,以下所示:

typealias Names<T> = Array<T>
typealias SubNames<T> = Names<T> 複製代碼

雖然沒有太大意義,可是語法上是正確的。

下面這樣套娃確定是不行的。

typealias R = R
 typealias L = List<L> typealias A<T> = List<A<T>>  typealias R1 = (Int) -> R2 typealias R2 = (R1) -> Int 複製代碼

上面的每一行代碼都是沒法編譯的。

可見性

頂層位置的 typealias 可使用可見性修飾符 public 、 private 、 internal 。同時,typealias 不能修改原有類型的可見性。舉個例子:

private class LongName{}
typealias ShortName = LongName // 'public' typealias exposes 'private' in expanded type LongName 複製代碼

上面的代碼會編譯失敗, public 的類型別名沒法應用在 private 的原類型上。類型別名和原類型的可見性必須保持一致。

導入同名類的處理

對於在同一個類中導入兩個同名類,一般的作法是, import 其中一個類,另外一個使用全限定名。以下所示:

fun main() {
 val user1 = User()  val user2 = com.test2.User() } 複製代碼

這樣或多或少不大美觀,可使用 typealias 處理一下。

typealias User2 = com.test2.User
 fun main() {  val user1 = User()  val user2 = User2() } 複製代碼

另外, import ... as ... 也能夠解決這個問題。

import com.test1.User
import com.test2.User as User2  fun main() {  val user1 = User()  val user2 = User2() } 複製代碼

最後

不妨翻翻你的代碼庫,看看有沒有可使用 typealias 進行優化的 「爛」 命名。若是有的話,歡迎來到評論區交流分享。

往期目錄object,史上最 「快」 單例 ?

本文使用 mdnice 排版

相關文章
相關標籤/搜索