01.15 多平臺應用的靜態編程語言Kotlin 1.4 和未來值得期待的地方

前言

Kotlin 1.4 將於 2020 年春季推出,其開發團隊在博客介紹了他們對 Kotlin 的願景:“讓 Kotlin 成為您所有工作的可靠伴侶,並是您執行任務的默認語言選擇。”因此,開發團隊將會讓開發者在所有平臺上都能使用 Kotlin。


多平臺應用的靜態編程語言Kotlin 1.4 和未來值得期待的地方

據開發團隊的介紹,Kotlin 1.4 將側重於質量和性能。因為對現在的 Kotlin 來說,提高整體體驗比添加新功能更加重要。此外,因為構建速度通常是用戶最關心的問題,所以開發團隊正在不斷改進工具鏈以解決此問題。但是逐步改進跟不上生產代碼庫的自然增長:儘管開發團隊加快了編譯速度,但用戶編寫了更多的代碼,使總體構建時間還不夠短。為此,開發團隊計劃重新實現編譯器以使其更快速。

新的編譯器

新編譯器實現的目標是變得更快速、統一 Kotlin 支持的所有平臺,並提供用於編譯器擴展的 API。這將是一項多年的工作,不過開發團隊已開始好一陣子了,因此新實現的某些部分將在 1.4 中發佈,可讓這個過程變得更加平順。

有些功能也已經發布了; 例如,如果開發者嘗試了用於類型推理的新算法,它是新編譯器的一部分。其他部分的處理方法相同。 也就是說,兩種版本都將在一段時間內可用,舊版本和新版本都將處於實驗模式; 當新的穩定後,它將成為默認版本。

新的前端(front-end)加速

開發團隊期望新編譯器提高的速度將來自新的前端實現。

為了提供一些背景信息,可以將編譯想成吸收源文件並將其逐步轉換為可執行代碼的管道。此管道的第一步俗稱為編譯器的前端。它解析代碼和命名、執行類型檢查等。此編譯器的這一部分也可以在 IDE 中使用,來高亮顯示語法錯誤、導航到定義並搜索項目中的符號用法。這是 kotlinc 如今花費最多時間的步驟,因此開發團隊希望使其更快。

當前的實現尚未完成,並且不會在 1.4 中到來。 但是,大多耗時的工作都是由它完成,因此可以預期提速的效果。基準測試(編譯 YouTrack 和 Kotlin 編譯器本身)表明,新前端的速度約為現有前端快 4.5 倍。

統一的後端和可擴展性

在前端完成對代碼的分析之後,後端將生成可執行文件。目前有三個後端:Kotlin / JVM,Kotlin / JS 和 Kotlin / Native。前兩個以往是獨立編寫的,沒有代碼共享。當啟動 Kotlin / Native 時,它是基於圍繞 Kotlin 代碼內部表示(internal representation)構建的新基礎架構的,該功能具有與虛擬機中的字節碼類似的功能。

現在,開發團隊計劃將其他兩個後端遷移到同一內部表示。因此,他們將共享許多後端邏輯並擁有統一的管道,以允許對所有目標僅執行一次大多數功能、優化和錯誤修復。

雖然正逐步遷移到新的後端,可是在 1.4 中,默認情況下不太可能啟用它們,但用戶將能夠選擇明確使用它們。

通用的後端基礎結構為跨平臺編譯器擴展打開了大門。可以在這管道中添加一些自定義處理和/或轉換,這些處理和轉換將自動適用於所有目標。在 1.4 中將不提供用於此類擴展的公開 API(該 API 稍後將被穩定),但開發團隊正在與合作伙伴 (其中包括已經構建其編譯器插件的 JetPack Compose )緊密合作。

新的語言功能:

Kotlin 1.4 將提供一些新的語言功能。

Kotlin 類的 SAM 轉換

社區已要求開發團隊引入對 Kotlin 類( KT-7770 )的 SAM 轉換的支持。如果僅將一個抽象方法的接口或類預計作為參數,則將 lambda 作為參數傳遞時,將應用 SAM 轉換。然後,編譯器自動將 lambda 轉換為實現抽象成員函數的類的實例。

SAM 轉換當前僅適用於 Java 接口和抽象類。該設計背後的最初想法是針對此類用例明確使用函數類型。然而,事實證明,函數類型和類型別名並不能涵蓋所有用例,開發者常常不得不僅在 Java 中保留接口才能對其進行 SAM 轉換。

與 Java 不同,Kotlin 不允許使用一種抽象方法對每個接口進行 SAM 轉換。開發團隊認為,使接口適用於 SAM 轉換的意圖應該明確。因此,要定義 SAM 接口,開發者需要使用 fun 關鍵字標記一個接口,以強調它可以用作功能性接口:

<code>fun interface Action {/<code>
<code>  fun run()/<code>
<code>}/<code>
<code>
<code>fun runAction(a: Action) = a.run()/<code>
<code>
<code>fun main() {/<code>
<code>  runAction {/<code>
<code>    println("Hello, KotlinConf!")/<code>
<code>  }/<code>
<code>}/<code>

請注意,僅在新的類型推斷算法中支持傳遞 lambda 而不是 fun 接口。

混合命名和位置參數

Kotlin 禁止將帶有顯式名稱的參數(“命名”)和不帶名稱的常規參數(“位置”)混合使用,除非僅將命名參數放在所有位置參數之後。但是,在一種情況下,這確實很煩人:當所有參數都保持在正確的位置而您想為中間的一個參數指定名稱時。Kotlin 1.4 將解決此問題,因此將能夠編寫如下代碼:

<code>fun f(a: Int, b: Int, c: Int) {}/<code>
<code>
<code>fun main() {/<code>
<code>  f(1, b = 2, 3)/<code>
<code>}/<code>

優化的委託屬性

開發團隊將改進 lazy 屬性和其他一些委託屬性的編譯方式。

通常,委託屬性可以訪問相應的 KProperty 反射對象。例如,當使用 Delegates.observable 時,可以顯示有關已修改屬性的信息:

<code>import kotlin.properties.Delegates/<code>
<code>
<code>class MyClass {/<code>
<code>  var myProp: String by Delegates.observable("") {/<code>
<code>    kProperty, oldValue, newValue ->/<code>
<code>    println("${kProperty.name}: $oldValue -> $newValue")/<code>
<code>  }/<code>
<code>}/<code>
<code>
<code>fun main() {/<code>
<code>  val user = MyClass()/<code>
<code>  user.myProp = "first"/<code>
<code>  user.myProp = "second"/<code>
<code>}/<code>

為了使之成為可能,Kotlin 編譯器會生成一個附加的語法成員屬性,即一個存儲所有 KProperty 對象的數組,這些對象表示在類內部使用的委託屬性:

<code>>>> javap MyClass/<code>
<code>
<code>public final class MyClass {/<code>
<code>  static final kotlin.reflect.KProperty[] $$delegatedProperties;/<code>
<code>  .../<code>
<code>}/<code>

但是,某些委託屬性不會以任何方式使用 KProperty。對於他們來說,在 $$delegatedProperties 中生成對象是次優的。Kotlin 1.4 版本將優化這種情況。如果委託屬性運算符是 inline,並且未使用 KProperty 參數,則不會生成相應的反射對象。最出色的示例是 lazy 屬性。lazy 屬性的 getValue 實現是 inline,並且不使用 KProperty 參數:

inline operator fun Lazy.getValue(thisRef: Any?, property: KProperty): T = value

從 Kotlin 1.4 開始,當定義 lazy屬性時,將不會生成相應的 KProperty實例。如果在類中使用的唯一委託屬性是 lazy屬性(以及符合此優化的其他屬性),則不會為類生成整個 $$delegatedProperties 數組:

<code>class MyOtherClass {/<code>
<code>  val lazyProp by lazy { 42 }/<code>
<code>}/<code>
<code>>>> javap MyOtherClass/<code>
<code>public final class MyOtherClass {/<code>
<code>  // no longer generated:/<code>
<code>  static final kotlin.reflect.KProperty[] $$delegatedProperties;/<code>
<code>  .../<code>
<code>}/<code>

尾隨逗號

可以在參數列表中的最後一個參數之後放置一個附加的尾隨逗號,然後交換行或添加新參數,而不必添加或刪除丟失的逗號。

其他主要變化

  • Kotlin 1.3.40 中引入了的有用的 typeof 函數將變得穩定並在所有平臺上得到支持。
  • 1.3.60 版本博客文章中已經描述了使您可以在 when 內啟用 break 和 continue 的功能。


分享到:


相關文章: