Kotlin 1.4 將於 2020 年春季推出,其開發團隊在博客介紹了他們對 Kotlin 的願景:「讓 Kotlin 成為您所有工作的可靠伴侶,並是您執行任務的默認語言選擇。」因此,開發團隊將會讓開發者在所有平台上都能使用 Kotlin。
據開發團隊的介紹,Kotlin 1.4 將側重於質量和性能。因為對現在的 Kotlin 來說,提高整體體驗比添加新功能更加重要。此外,因為構建速度通常是用戶最關心的問題,所以開發團隊正在不斷改進工具鏈以解決此問題。但是逐步改進跟不上生產代碼庫的自然增長:儘管開發團隊加快了編譯速度,但用戶編寫了更多的代碼,使總體構建時間還不夠短。為此,開發團隊計劃重新實現編譯器以使其更快速。
新編譯器實現的目標是變得更快速、統一 Kotlin 支持的所有平台,並提供用於編譯器擴展的 API。這將是一項多年的工作,不過開發團隊已開始好一陣子了,因此新實現的某些部分將在 1.4 中發布,可讓這個過程變得更加平順。
有些功能也已經發布了; 例如,如果開發者嘗試了用於類型推理的新演算法,它是新編譯器的一部分。其他部分的處理方法相同。 也就是說,兩種版本都將在一段時間內可用,舊版本和新版本都將處於實驗模式; 當新的穩定后,它將成為默認版本。
開發團隊期望新編譯器提高的速度將來自新的前端實現。
為了提供一些背景信息,可以將編譯想成吸收源文件並將其逐步轉換為可執行代碼的管道。此管道的第一步俗稱為編譯器的前端。它解析代碼和命名、執行類型檢查等。此編譯器的這一部分也可以在 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 類( KT-7770 )的 SAM 轉換的支持。如果僅將一個抽象方法的介面或類預計作為參數,則將 lambda 作為參數傳遞時,將應用 SAM 轉換。然後,編譯器自動將 lambda 轉換為實現抽象成員函數的類的實例。
SAM 轉換當前僅適用於 Java 介面和抽象類。該設計背後的最初想法是針對此類用例明確使用函數類型。然而,事實證明,函數類型和類型別名並不能涵蓋所有用例,開發者常常不得不僅在 Java 中保留介面才能對其進行 SAM 轉換。
與 Java 不同,Kotlin 不允許使用一種抽象方法對每個介面進行 SAM 轉換。開發團隊認為,使介面適用於 SAM 轉換的意圖應該明確。因此,要定義 SAM 介面,開發者需要使用 fun
關鍵字標記一個介面,以強調它可以用作功能性介面:
fun interface Action {
fun run()
}
fun runAction(a: Action) = a.run()
fun main() {
runAction {
println("Hello, KotlinConf!")
}
}
請注意,僅在新的類型推斷演算法中支持傳遞 lambda 而不是 fun 介面
。
Kotlin 禁止將帶有顯式名稱的參數(「命名」)和不帶名稱的常規參數(「位置」)混合使用,除非僅將命名參數放在所有位置參數之後。但是,在一種情況下,這確實很煩人:當所有參數都保持在正確的位置而您想為中間的一個參數指定名稱時。Kotlin 1.4 將解決此問題,因此將能夠編寫如下代碼:
fun f(a: Int, b: Int, c: Int) {}
fun main() {
f(1, b = 2, 3)
}
開發團隊將改進 lazy
屬性和其他一些委託屬性的編譯方式。
通常,委託屬性可以訪問相應的 KProperty
反射對象。例如,當使用 Delegates.observable
時,可以顯示有關已修改屬性的信息:
import kotlin.properties.Delegates
class MyClass {
var myProp: String by Delegates.observable("<no name>") {
kProperty, oldValue, newValue ->
println("${kProperty.name}: $oldValue -> $newValue")
}
}
fun main() {
val user = MyClass()
user.myProp = "first"
user.myProp = "second"
}
為了使之成為可能,Kotlin 編譯器會生成一個附加的語法成員屬性,即一個存儲所有 KProperty
對象的數組,這些對象表示在類內部使用的委託屬性:
>>> javap MyClass
public final class MyClass {
static final kotlin.reflect.KProperty[] $$delegatedProperties;
...
}
但是,某些委託屬性不會以任何方式使用 KProperty
。對於他們來說,在 $$delegatedProperties
中生成對象是次優的。Kotlin 1.4 版本將優化這種情況。如果委託屬性運算符是 inline
,並且未使用 KProperty
參數,則不會生成相應的反射對象。最出色的示例是 lazy
屬性。lazy
屬性的 getValue
實現是 inline
,並且不使用 KProperty
參數:
inline operator fun <T> Lazy<T>.getValue(thisRef: Any?, property: KProperty<*>): T = value
從 Kotlin 1.4 開始,當您定義 lazy
屬性時,將不會生成相應的 KProperty
實例。如果在類中使用的唯一委託屬性是 lazy
屬性(以及符合此優化的其他屬性),則不會為類生成整個 $$delegatedProperties
數組:
class MyOtherClass {
val lazyProp by lazy { 42 }
}
>>> javap MyOtherClass
public final class MyOtherClass {
// no longer generated:
static final kotlin.reflect.KProperty[] $$delegatedProperties;
...
}
可以在參數列表中的最後一個參數之後放置一個附加的尾隨逗號,然後交換行或添加新參數,而不必添加或刪除丟失的逗號。
typeof
函數將變得穩定並在所有平台上得到支持。when
內啟用 break
和 continue
的功能。
[admin
]