Kotlin 1.4-M1 現已發佈!


我們高興地宣佈新的主要版本的第一個預覽版本:Kotlin 1.4-M1。

幾個月以前,我們針對 Kotlin 1.4 值得期待的亮點發布了一則公告。隨着發佈臨近,我們現在提供一個預覽版本,讓大家能夠試用一些新功能。

在這篇博文中,我們將重點介紹 1.4-M1 中的以下新功能和主要改進:

默認啓用一種功能更加強大的新類型推理算法。

協定現在可用於 final 成員函數。

☞Kotlin/JVM 編譯器現在可在字節碼中爲 Java 8 和更高版本生成類型註解。

☞Kotlin/JS 的新後端爲生成的工件帶來大幅提升。

☞標準庫中的漸進式變更:完成棄用週期並棄用一些額外的部分。

您可以在變更日誌中找到完整的變更列表。我們要一如既往地感謝外部貢獻者。

我們強烈建議您試用預覽版,並感謝您在我們的問題跟蹤器中提供任何反饋。

功能更加強大的類型推理算法

Kotlin 1.4 將使用一種功能更加強大的新類型推理算法。您之前已經可以通過指定編譯器選項在 Kotlin 1.3 中試用這種新算法,現在則可以默認使用。您可以在 YouTrack 中找到新算法中修復的完整問題列表。在這篇博文中,我們將重點介紹一些最值得注意的改進。

Kotlin 函數和接口的 SAM 轉換

SAM 轉換讓您可以在預期出現一個包含“單抽象方法”的接口時傳遞 lambda。之前,您只能在 Kotlin 中使用 Java 方法和 Java 接口時應用 SAM 轉換,現在您也可以將它與 Kotlin 函數和接口一起使用。

Kotlin 現在支持 Kotlin 接口的 SAM 轉換。請注意,在 Java 中的操作不同:您需要明確地標記函數接口。使用 fun 關鍵字標記接口後,在接口預計爲參數時,您都可以將 lambda 作爲參數傳遞:

您可以在之前的博文中閱讀與此相關的更多詳細信息。

Kotlin 從最開始就支持 Java 接口的 SAM 轉換,但有一種情況不受支持,在使用現有 Java 庫時會令人很煩。如果您調用了將兩個 SAM 接口作爲參數的 Java 方法,兩個參數需要都爲 lambda 或常規對象。不可以將一個參數作爲 lambda 而另一個參數作爲對象來傳遞。新算法修復了這個問題,在任何情況下您都可以傳遞 lambda,而不是 SAM 接口,這正是您期待的運作方式。

在更多用例中自動推斷類型

新推理算法會爲許多用例推斷類型,而舊推理要求您明確地指定它們。例如,在以下示例中,lambda 參數 it 的類型將正確推斷爲 String?:

在 Kotlin 1.3 中,您需要引入顯式 lambda 參數,或者將 to 替換爲包含顯式泛型參數的 Pair 構造函數纔可以。

lambda 中最後一個表達式的智能轉換

在 Kotlin 1.3 中,lambda 中的最後一個表達式不是智能轉換,除非您指定預期的類型。因此,在以下示例中,Kotlin 1.3

將 String? 推斷爲 result 變量的類型:

在 Kotlin 1.4 中,藉助新的推理算法,lambda 中的最後一個表達式可以實現智能轉換,並且這種更精確的新類型用於推斷結果 lambda 類型。因此,result 變量的類型變爲 String。

在 Kotlin 1.3 中,您經常需要添加顯式轉換(!! 或類型轉換,例如 as String)來使這種情況奏效,而現在這些轉換不再必要。

可調用的引用的智能轉換

在 Kotlin 1.3 中,您無法訪問智能轉換類型的成員引用。現在,您可以:

在動物變量智能轉換爲特定類型 Cat 和 Dog 之後,您可以使用不同的成員引用 animal::meow 和 animal::woof。在類型檢查之後,您可以訪問與子類型對應的成員引用。

更出色的可調用引用推理

現在,可以更方便地使用包含默認參數值的函數的可調用引用。例如,以下 foo 函數的可調用引用可以解釋爲獲取一個 Int 參數或不獲取參數:


更出色的委託屬性推理

之前,在分析遵循 by 關鍵字的委託表達式時,不會考慮委託屬性的類型。例如,之前不會編譯以下代碼,但現在編譯器可以正確地將 old 和 new 參數的類型推斷爲 String?:

語言變更

大多數語言變更在之前的博文中已有介紹:

☞Kotlin 類的 SAM 轉換

☞混合命名和位置參數

☞優化的委託屬性

☞尾隨逗號

☞在 when 中換行並繼續

☞尾遞歸函數的變更

在這篇博文中,我們將重點介紹與協定相關的一些小幅改進。

協定支持

定義自定義協定的語法仍爲實驗性功能,但我們已支持幾種新的用例,其中協定可能會很有用。您現在可以使用具體化的泛型類型參數來定義協定。

例如,您可以爲 assertIsInstance 函數實現以下協定:

由於 T 類型參數已具體化,您可以在函數主體中檢查它的類型。現在,這一點在協定中也可以實現。一個包含斷言消息的相似函數稍後將添加到 kotlin.test 庫中。

另外,您現在還可以爲 final 成員定義自定義協定。之前,爲成員函數定義協定是完全禁止的,因爲在層次結構中爲一些成員定義協定意味着也需要定義相應協定的層次結構,而且在設計和討論方面也存在問題。不過,如果成員函數爲 final,且不會重寫任何其他函數,則可以安全地爲它定義協定。

標準庫變更

排除棄用的實驗性協同程序

在1.3.0中,已棄用

kotlin.coroutines.experimental API,而支持 kotlin.coroutines。在 1.4-M1 中,我們

將 kotlin.coroutines.experimental 從標準庫中移除,徹底完成了它的棄用週期。對於仍在 JVM 上使用它的用戶,我們提供兼容性工件 kotlin-coroutines-experimental-compat.jar 以及所有實驗性協同程序 API。我們準備將它發佈到 Maven 幷包含在標準庫以外的 Kotlin 分發中。當前,我們已經將它與 1.4-M1 工件一同發佈到 bintray 存儲庫。

移除棄用的 mod 運算符

另一個棄用的函數是數值類型的 mod 運算符,這個運算符會在除法運算之後計算餘數。在 Kotlin 1.1 中,此運算符被 rem() 函數替代。現在,我們將它從標準庫中完全移除。

從浮動類型到 Byte 和 Short 轉換的棄用

標準庫包含將浮點數轉換爲整數類型的函數:toInt()、toShort()、toByte()。將浮點數轉換爲 Short 和 Byte 可能導致意外結果,因爲值範圍和變量大小較小。爲了避免這種問題,從 1.4-M1 起,我們將棄用 Double 和 Float 類型的函

數 toShort() 和 toByte()。如果您仍需要將浮點數轉換

爲 Byte 或 Short,請進行兩步轉換:首先轉換爲 Int,然後轉換爲目標類型。

常用反射 API

我們修改了常用反射 API。現在,它僅包含可以在所有三個目標平臺(JVM、JS、Native)上使用的成員,這樣您就可以確保同一代碼可以用於任何一個平臺。

use() 和時間測量函數的新協定

我們將在標準庫中擴大協定的使用。在 1.4-M1 中,我們添加了一些協定,可以爲 use() 函數與時間測量函數 measureTimeMillis() 和 measureNanoTime() 聲明代碼塊的單次執行。

Kotlin 反射的 Proguard 配置

從 1.4-M1 開始,我們爲 kotlin-reflect.jar 中的 Kotlin 反射嵌入了 Proguard/R8 配置。這樣,使用 R8 或 Proguard 的大多數 Android 項目無需額外的配置就可以使用 kotlin-reflect。您無需再爲 kotlin-reflect 內部項複製粘貼 Proguard 規則。但是請注意,您仍需要明確地列出要在上面反射的所有 API。

Kotlin/JVM

從 1.3.70 版起,Kotlin 可以在 JVM 字節碼(目標版本 1.8+)中生成類型註解,以便它們在運行時可用。社區請求此功能已有一段時間,因爲它讓使用某些現有 Java 庫更加容易,並且爲新庫的作者提供了更多功能。

在以下示例中,可以將 String 類型上的 @Foo 註解發出到字節碼,然後由庫代碼使用:

有關如何在字節碼中發出類型註解的詳細信息,請參閱 Kotlin 1.3.70 版本博文的相關部分。

Kotlin/JS

對於 Kotlin/JS,此里程碑包含對 Gradle DSL 的變更,這是包含新的 IR 編譯器後端的第一個版本,新編譯器帶來了優化和新功能。

Gradle DSL 變更

在 kotlin.js 和 multiplatform Gradle 插件中,引入了一個重要的新設置。在 build.gradle.kts 文件中的目標塊內,現已支持 produceExecutable(),如果您想要在構建時生成 .js 工件,則必須使用它:

如果您要編寫 Kotlin/JS 庫,可以忽略 produceExecutable()。使用新的 IR 編譯器後端(更多詳細信息如下)時,忽略此設置意味着不會生成可執行的 JS 文件(因此,構建過程的速度加快)。會在 build/libs 文件夾中生成一個 klib 文件,此文件可以在其他 Kotlin/JS 項目中使用,或在同一項目中用作依賴項。如果您不明確指定 produceExecutable(),此行爲會默認發生。

使用 produceExecutable() 會生成能夠從 JavaScript 生態系統執行的代碼:使用其自己的入口點或作爲 JavaScript 庫。這將生成實際的 JavaScript 文件,這些文件可以在節點解釋器中運行,在 HTML 頁面中嵌入並在瀏覽器中執行,或者用作 JavaScript 項目的依賴項。

請注意,當目標爲新的 IR 編譯器後端(更多詳細信息如下) 時,produceExecutable() 會始終按目標生成一個單獨的 .js 文件。

當前,不支持在多個生成的工件之間刪除重複或拆分代碼。您可以期待 produceExecutable() 的此行爲在後續里程碑中發生變化。此選項的命名還與未來的變更有關。

新後端

Kotlin 1.4-M1 是包含可用於 Kotlin/JS 目標的新 IR 編譯器後端的第一個版本。此後端是顯著改進的優化的基礎,也是 Kotlin/JS 與 JavaScript 和 TypeScript 交互方式變更的決定性因素。下面重點介紹的功能都針對新的 IR 編譯器後端。儘管還沒有默認啓用,我們鼓勵您在項目中試用它,開始爲新的後端準備庫,並向我們提供反饋,記錄遇到的問題。

使用新後端

要開始使用新後端,請在您的 gradle.properties 文件中設置下列標誌:

如果需要爲 IR 編譯器後端和默認後端生成庫,您還可以將此標誌設置爲 both。此標誌的確切功能在本博文的 Both 模式部分中進行了介紹。此標誌非常有必要,因爲新的和默認編譯器後端不兼容二進制文件。

無二進制兼容性

新的 IR 編譯器後端的主要變化是缺少與默認後端的二進制兼容性。在 Kotlin/JS 的兩種後端之間缺少這種兼容性意味着使用新的 IR 編譯器後端創建的庫無法用於默認後端,反之亦然。

如果您想要將 IR 編譯器後端用於項目,則需要將所有 Kotlin 依賴項更新爲支持此新後端的版本。由 JetBrains 在 Kotlin 1.4-M1 中面向 Kotlin/JS 發佈的庫已包含與新的 IR 編譯器後端搭配使用而需要的所有工件。依賴這種庫時,Gradle 會自動選擇正確的工件(即無需指定 IR 特定的座標)。請注意,一些庫(如 kotlin-wrappers)在使用新的 IR 編譯器後端時會出問題,因爲它們依賴於默認後端的特定特性。我們已經意識到這一點,以後將改進此功能。

如果您是庫作者,期待着能夠兼容當前的編譯器後端和新的 IR 編譯器後端,另請查看本博文的“Both 模式”部分。下一部分將詳細介紹新編譯器的好處和差異。

優化的 DCE

與默認後端相比,新 IR 編譯器後端進行了顯著優化。生成的代碼能夠更好地與靜態分析器一同使用,甚至還可以通過 Google 的 Closure Compiler 從新 IR 編譯器後端運行生成的代碼,並使用它的高級模式優化(請注意,Kotlin/JS Gradle 插件對此不提供特定支持)。

最明顯的變化是生成工件的代碼大小。消除死代碼的改進方法使工件可以大幅縮小。例如,這將使“Hello, World!”Kotlin/JS 程序減小到小於 1.7 KiB。對於更復雜的(演示)項目,例如使用 kotlinx.coroutines 的此示例項目,數值也會顯著變化,希望事實可以說明這一切:

如果您還不相信,請自己試試。Kotlin 1.4-M1 已爲兩種後端默認啓用 DCE 和捆綁!

將聲明導出到 JavaScript 中

使用 IR 編譯器後端時,標記爲公開的聲明將不再自動導出(即使名稱毫無邏輯的版本也不會)。這是因爲 IR 編譯器的 closed-world 模型假設導出的聲明會明確地註解,跟上一個一樣,這也是一個有助於優化的因素。

要使 JavaScript 或 TypeScript 可以從外部使用頂級聲明,請使用 @JsExport 註解。在以下示例中,我們使 KotlinGreeter(及其方法)和 farewell() 可以從 JavaScript 使用,但使 secretGreeting() 僅適用於 Kotlin:


預覽:TypeScript 定義

在新的 Kotlin/JS IR 編譯器中,我們很高興展示的另一個功能是從 Kotlin 代碼生成 TypeScript 定義。在開發混合應用時,JavaScript 工具和 IDE 可以使用這些定義來提供自動補全、支持靜態分析器,並更輕鬆地在 JS 和 TS 項目中包含 Kotlin 代碼。

在配置爲使用 produceExecutable() 的項目中,對於使用 @JsExport(參見上文)標記的頂級聲明,將生成包含 TypeScript 定義的 .d.ts 文件。對於上面的代碼段,它們是這樣的:

在 Kotlin 1.4-M1 中,可以在未使用 webpack 打包的相應 JavaScript 代碼旁

的 build/js/packages/<package_name>/kotlin 中找到這些聲明。請注意,由於現在只是預覽版本,它們默認沒有添加到 distributions 文件夾中。您可以期待此行爲將來會發生變化。

Both 模式

爲了讓庫維護者更方便地遷移到新的 IR 編譯器後端,爲 gradle.properties 中的 kotlin.js.compiler 標誌引入了一個額外設置:

在 both 模式下,從您的源代碼構建庫時會使用 IR 編譯器後端和默認編譯器後端(因此得名)。這意味着會生成用於 Kotlin IR 的 klib 文件和用於默認編譯器的 js 文件。在同一個 Maven 座標下發布時,Gradle 會根據用例自動選擇正確的工件:爲舊編譯器選擇 js,爲新編譯器選擇 klib。這表示您可以使用新的 IR 編譯器後端編譯和發佈庫,新的 IR 編譯器後端適用於已升級到 Kotlin 1.4-M1 的項目和使用任意一種編譯器後端的項目。這有助於確保仍在使用默認後端的用戶不會受影響——假定他們已經將項目升級到 1.4-M1。

請注意,如果依賴項和您的項目使用 both 模式構建,仍然存在會導致 IDE 無法正常解析庫引用的問題。我們已經意識到此問題,將很快解決。

Kotlin/Native

默認支持 Objective-C 泛型

歷史版本的 Kotlin 在 Objective-C 互操作中爲泛型提供了實驗性支持。要從 Kotlin 代碼使用泛型生成框架標頭,您過去必須使用 -Xobjc-generics 編譯器選項。在 1.4-M1 中,此行爲已成爲默認行爲。在一些情況下,這可能會破壞調用 Kotlin 框架的現有 Objective-C 或 Swift 代碼。要不使用泛型編寫框架標頭,請添加 -Xno-objc-generics 編譯器選項。

請注意,文檔中列出的所有詳細信息和限制仍有效。

在 Objective-C/Swift 互操作中處理異常的變更

在 1.4 中,針對轉換異常的方式,我們將稍微變更從 Kotlin 生成的 Swift API。Kotlin 和 Swift 之間的錯誤處理存在着根本的區別。所有 Kotlin 異常都未經檢查,而 Swift 只包含檢查的錯誤。因此,要使 Swift 代碼感知預期的異常,Kotlin 函數應使用 @Throws 註解標記,此註解會指定一系列潛在的異常類。
編譯爲 Swift 或 Objective-C 框架時,擁有或要繼承 @Throws 註解的函數在 Objective-C 中表示爲產生方法的 NSError*,在 Swift 中表示爲 throws 方法。


之前,除了 RuntimeException 和 Error 以外的任何異常都傳播爲 NSError。在 1.4-M1 中,我們更改了此行爲。現在,僅對一些異常引發 NSError,這些異常是指定爲 @Throws 註解的參數的類實例(或其子類)。影響 Swift/Objective-C 的其他 Kotlin 異常被認爲未經處理且會引起程序終止。

性能改進

我們會堅持不懈地改進 Kotlin/Native 編譯和執行的整體性能。在 1.4-M1 中,我們會爲您提供新的對象分配器,它在一些基準上能夠以高達兩倍的速度運行。目前,新分配器仍處於實驗階段,默認不會使用;您可以使用 -Xallocator=mimalloc 編譯器選項切換到此分配器。

兼容性

請注意,在一些極端情況下,Kotlin 1.4 不會向後兼容 1.3。所有這些情況都已接受語言委員會的仔細檢查,將列在“兼容性指南”(類似於此指南)中。當前,您可以在 YouTrack 中找到此列表。

重載解析規則可能會有小幅變化。如果您有多個包含相同名稱和不同簽名的函數,在 Kotlin 1.4 中調用的函數可能會與在 Kotlin 1.3 中選擇的函數不同。不過,這隻會發生在一些極端情況下,我們認爲實際只會在極少的情況下出現這種現象。我們還假設重載函數在實際中行爲類似,最終逐個調用,因此,這些變更不會影響程序行爲。不過,如果您想通過泛型編寫棘手的代碼,並具有不同級別的多個重載,請加以注意。所有這些情況都會列在上述兼容性指南中。

預發佈說明

請注意,後向兼容性保證不涵蓋預發佈版本。功能和 API 在後續版本中可能發生變化。在我們發佈最終 RC 時,預發佈版本產生的所有二進制文件都會被編譯器禁止,您需要重新編譯通過 1.4‑Mx 編譯的所有內容。

如何試用

和往常一樣,您可以在play.kotl.in上在線試試Kotlin

在 IntelliJ IDEA 和 Android Studio 中,您可以將 Kotlin 插件更新爲 1.4-M1。查看如何執行此操作。

如果您想處理在安裝該預覽版之前創建的現有項目,則需要在 Gradle 或 Maven 中針對預覽版配置您的構建。

您可以從 Github 發佈頁面下載命令行編譯器。

您可以使用隨此版本一起發佈的以下庫:

☞kotlinx.atomicfu 版本:0.14.2-1.4-M1

☞kotlinx.coroutines 版本:1.3.5-1.4-M1

☞kotlinx.serialization 版本:0.20.0-1.4-M1

☞ktor 版本:1.3.2-1.4-M1

您也可以在此處找到版本詳細信息和兼容庫的列表。分享您的反饋

如果您發現錯誤並在 YouTrack 問題跟蹤器中報告,我們將不勝感激。我們將盡力在最終版本之前修復所有重要問題,也就是說,您不用等到下一個 Kotlin 版本即可看到問題得到解決。

如果您有任何問題並想參與討論,歡迎加入 Kotlin Slack 中的 #eap 頻道(在此處獲取邀請)。在此頻道中,您還可以獲取有關新預覽版本的通知。

Let’s Kotlin!

外部貢獻

特別感謝 Zac Sweers 將 Proguard 配置嵌入 kotlin-reflect 的貢獻。

我們要感謝所有的外部貢獻者,此版本中包含了他們的拉取請求。

點擊原文即可查看詳情:

☞Steven Schäfer

☞Toshiaki Kameyama

☞pyos

☞Mads Ager

☞Mark Punzalan

☞Juan Chen

☞Kristoffer Andersen

☞Alfredo Delli Bovi

☞Jinseong Jeon

☞Jonathan Leitschuh

☞Sebastian Schuberth

☞Ivan Gavrilovic

☞David Schreiber-Ranner

☞Miguel Serra

☞Alex Chmyr

☞Fleshgrinder

☞Aleksey Kladov

☞Will Boyd

☞Dominic Fischer

☞Kenji Tomita

☞Stéphane Nicolas

☞Tillmann Berg

☞Kevin Bierhoff

☞Tsvetan

點擊查看歷史資訊

JetBrains教育產品:課程創新者的新功能

2018開發人員生態系統:C和C++的主要趨勢

JetBrains 將提供免費開源教育產品!

2018開發人員生態系統調查,什麼是編程世界的驅動力

戳“閱讀原文”查看更多

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