來為Kotlin 1.3.60正式版的釋出而歡呼!除了質量的改進,下面是該版本的關鍵更新:
- 最佳化了
內聯
類的比較行為 - 改進了測試工具,J2K轉換器,Kotlin Gradle指令碼編輯工具
- Kotlin/Native支援更多平臺
- 改善了IDE對Kotlin/MPP的體驗
- 對於Kotlin/JS,新增了源對映的,並改善平臺測試執行器的整合
- 提供Kotlin1.4中已有實現的預覽
你可以在更新日誌中查閱完整的更新列表。我們仍然非常感謝所有外部的貢獻者.
更多細節請讓我娓娓道來。
語言的變化
小版本迭代不會帶來語言的變更,除了小規模的改進(如改進令人迷惑的錯誤資訊)或實驗特性的更新(像內聯
類)。如想提前嚐鮮Kotlin1.4,請閱讀相應的文件。
內聯類的改進
對於內聯
類的比較,其類以內的資料型別會有一次不必要的裝箱行為。但自1.3.60版本開始,裡面資料型別的比較得以最佳化:
每個內聯
類的位元組碼都會生成一個特殊的靜態方法equals-impl0
,用於比對類中的資料型別。當你在非裝箱例項上進行比對時,其隱式呼叫會避免額外的裝箱行為。
請注意,暫時無法為內聯類複寫equals/hashCode
方法。生成的equals-impl0
方法只是簡單比較資料。在未來的版本,當允許內聯類自定義equals
方法時,內部仍然會呼叫相同的equals-imp0
方法。
由於相容性的原因,該最佳化只適用於Kotlin1.4版本的kotlin.Result
類。
錯誤資訊的改進
在小部分的情況下,編譯錯誤資訊並不能明確地告知你錯誤發生的原因。我們嘗試改善並減少會帶來疑惑的錯誤資訊。
Kotlin支援trailing lambda convention:lambda允許在括號之外。同樣允許lambda另起一行。但當編譯器認為新一行的大括號是函式的引數時,可能會產生歧義:
對於這種情況的錯誤資訊現在得以改進了。你可以執行簡單的自動修復方案:在上一行的末尾插入一個分號。(沒錯,Kotlin有些時候也是需要分號的!)
另一個值得強調的情況是針對可變惰性常量。惰性
變數設計上是隻讀的,但這設計可能會引起疑惑。現在其錯誤資訊得以改進並提供了自動的修復捷徑:
如果你遇到其他容易疑惑的用例,或你缺少部分非常有用的修復捷徑,請在問題跟蹤器提交這些請求。
IntelliJ IDEA支援
Scratches和Worksheets
我們重新設計並改良了Scratch檔案,其目的是允許你以最小的程式碼庫進行試驗。現在可以在不同的視窗更方便地檢視結果。涉及多行輸出的結果會被包裹起來,同時高亮特定行。
有些時候Scratch檔案並不能很好地執行。在如建立demo專案,展示特性等出於教學目的的場景下,你會更傾向於在專案內部而非外部去建立這些用例。對於這些需求,請使用Kotlin的Worksheets:
Kotlin Worksheets從概念上和技術上來說,與Scratch非常相似:你可以使用程式碼庫並立即檢視結果。兩者之間的主要區別在於Worksheets是專案的一部分,這意味著可以透過VCS管理,而Scratches設計初衷是專案外的一部分。
build.gradle.kts
我們仍致力於提高你在編寫Kotlin Gradle構建指令碼的體驗。著重強調的效能改善已經完成。我們會繼續與Gradle緊密合作以不斷改進。
Debugging改善
現在你可以在Kotlin函式中設定斷點了。偵錯程式會在進入或退出對應函式時暫停。你同樣可以根據需求設定條件:
自動補全和匯入的改善
幾個已知的錯誤已經被修復了,如自動補全在包名和本地變數名重疊時的情況:
現在當你為列舉重新定義名稱時,它的成員能在自動補全候選框中正常顯示了:
如果你用到invoke
這樣的可省略語法運算子,IntelliJ IDEA建議你使用自動匯入:
新的Java-to-Kotlin轉換器
我們為新的Java-to-Kotlin加入了很多優秀的設計。解決了很多特殊情況,例如,現在能正確分析並轉換靜態匯入和各種用法的集合,集合將能正確轉換成可變或只讀,無論該集合是否為通用引數。
現在,當你一次轉換多個檔案時,它們將會被共同分析,每個檔案的內容都會影響最後輸出的結果。 例如,你將null
作為String
引數傳遞給Java中的foo
函式,則轉換後的Kotlin函式引數是String?
:
新的轉換器現在將被預設啟用。
Eclipse IDE外掛的更新
我們非常高興地宣佈kotlin-eclipse外掛現已支援單個模組的實驗性增量編譯。在eclipse設定的Kotlin | Building
部分勾”incremental compilation”以嘗試該功能。由於這是一個實驗性特性,我們非常歡迎你的任何反饋!
Kotlin/Multiplatform
我們將重心放在MPP工具上了,若有和你的此前預期不一致的地方,請嘗試新的改進!
儘管未來的正式版會在Kotlin的多平臺方面帶來更強大的功能,但當前版本著重改進/修復IDE的許多可用性問題。 尤其我們極大增強了一些“create expect
”快速修復的功能。
Kotlin/Native
Kotlin/Native編譯器獲得了很多新功能:
- 和最新工具的相容性:XCode和LLVM 8.0
- 更多的新平臺:
- watchOS
watchos_x86
watchos_arm64
watchos_arm32
- tvOS
tvos_x64
tvos_arm64
- Android (native)
android_x86
android_x64
- watchOS
- 針對正式版二進位制檔案的iOS崩潰報告的實驗性symbolication(包括LLVM內聯程式碼,比XCode可解碼的程式碼更為先進)。
- 對Kotlin物件的Objective-C弱引用/共享引用的執行緒安全追蹤。
- 支援對
suspend
callable的引用. - “無限”可變引數函式 (受限於JVM限制)
- work queue將能和任何上下文/執行緒關聯,而不僅僅是透過
Worker.start
臨時建立的上下文/執行緒。
通用Kotlin/Multiplatform命令列解析器
你們可能有人已經注意到kotlinx.cli
專案已經停更了幾個月。 我們很高興分享該專案,其中大部分的程式碼已被重寫,並且它也包含在此版本的Kotlin/Native編譯器中。
我們感謝早期新技術開荒使用者的反饋! 你可以檢視某些示例(俄羅斯方塊, CSV解析器, 影片播放器)的用法,和內部的用法。
效能
儘管Kotlin/Native編譯器還未對效能進行深度最佳化。但該正式版所帶來的一些速度提升已足以讓人驚訝。
對於大型專案,透過直接從klib(而不是原始碼)生成本機庫來提高了編譯速度。
執行時效能也得到了改善:介面呼叫現在快了5倍,型別檢查快了50倍!
修復
- 對於內聯程式碼缺少debug所需要資訊:部分內聯最佳化會遺漏更新對於原始碼行號和實際位元組碼位置間的對映,這會導致設定斷點的行為產生異常,導致超出目標位置的情況。我們已經提高了它們的記性,現在斷點能正常執行了。
- 向可變引數傳遞
null
當向具有可變引數
的函式傳遞null
時,例如:platform.posix.printf(“%p”, null)編譯器會因為無法判斷實際的型別而崩潰。請注意,現在我們會將該值視為COpaquePointer
:無型別/ void指標,等效於C中的void *。 - 為iOS/macOS的負值拆箱有些時候,處理負數字節會導致嚴重的崩潰;這是LLVM上的一個BUG,我們建議透過手動的方案去解決。從當前正式版開始,這個解決方案由編譯器自動執行。
Kotlin/JS
在Kotlin/JS領域,org.jetbrains.kotlin.js
新外掛所帶來的改進將能提升你的生活品質和簡化你的工作。尤其是對源對映的支援和測試執行器的改進。
源對映
在Kotlin 1.3.60,可以透過org.jetbrains.kotlin.js
Gradle外掛自動為以JavaScript為目標的程式碼生成源對映。當你遇到錯誤時它可以提供可供閱讀的堆疊跟蹤資訊,這使你可以更輕鬆地除錯自己的程式碼,斷點,程式碼註釋,區域性變數等的支援,將是瀏覽器開發工具的黑科技。下一段落將介紹如何簡化JS平臺的測試工作。
測試執行器的改進
當你在JS平臺上執行測試,生成的Gradle報告將包含常規通道的標準輸出(即log
,warn
,error
)。該功能允許在Node.js或瀏覽器平臺上啟用。這與源對映的整合使測試的堆疊跟蹤更易於閱讀,並方便與程式碼結合分析——檔名和行號直接指向你的Kotlin原始碼:
JS平臺已支援測試過濾器,意味著可以有選擇性地執行測試,而無需每次都得完整執行所有測試任務。你可以透過在Gradle命令列中指定--tests
標記使用該功能:
你也可以使用IntelliJ IDEA中的 gutter圖示來執行單個測試或指定組合的測試:
Kotlin1.4即將到來的變化
Kotlin 1.4將計劃在2020年釋出。但你可以透過指定相應的語言版本來嘗試一些已實現的特性:
請注意當前Kotlin1.4還在試驗性狀態
NPE斷言
透過設定apiVersion
到1.4
,你可以看到此前介紹過的空檢查最佳化。下面的程式碼將會丟擲一個NullPointerException
,而非IllegalStateException
以及舊的錯誤資訊"JavaCode.getNull() must not be null"
:
when
裡的break和continue
Kotlin1.4其中一個語言層面上的變化是允許在when
裡面使用break
和continue
了。當前禁止使用不帶標籤的break
和continue
,是因為這些關鍵字作為when
的fall-through的可能候選。 但是使用標籤非常麻煩,因此break
和continue
能在外部存在迴圈下正確執行 :
when
的fall-through行為有待設計。
尾遞迴函式的變化
我們準備修復尾遞迴函式在”特殊情況”下的一些特定行為。
預設函式的初始化順序
當你的尾遞迴函式定義了具有副作用的預設值時,這個更改才有意義。 在Kotlin 1.3中,tailrec
函式內的預設值的初始化順序是錯誤的:預設值初始化順序是從尾向頭,即使反之亦然,從頭向尾,這個規則同樣適用於普通函式。
透過下面的例子可以明顯看到區別:
在Kotlin1.3,輸出是:
在Kotlin1.4,輸出是:
我們希望實際情況中儘量不要採取這種寫法。 (但如果由於某種原因你使用了這種複雜組合的語言特性,請注意這一即將到來的變化。)
在Kotlin 1.3中,結合使用open和tailrec修飾符是一個警告,在Kotlin 1.4中,它將成為錯誤。 請注意,這是一個“重大變化”:過去可以正常工作的程式碼不再起作用,但是我們不希望這種情況在實踐中使用。
禁止同時使用open
tailrec
修飾函式
在Kotlin 1.3中,同時使用open
和tailrec
修飾符只是一個warning,但在Kotlin 1.4中,它將是一個error。 請注意,這是一個“有破壞性的變化”:過去可以正常工作的程式碼將報錯,但是我們不建議在實際環境中採取如此寫法。
目前尚無法明確open
尾遞迴函式的行為該以尾遞迴為主還是oepn
函式為主。 在Kotlin 1.3中,open
修飾符會被“忽略”,但這容易讓人產生疑惑:
這段程式碼的輸出是:
foo
的函式行為更傾向於尾遞迴函式的預期:它呼叫了自身並在底層執行了最佳化
當我們從A
的foo
函式中去除tailrec
修飾符,它的輸出會變成:
現在foo
函式的行為更符合open
函式的預期:首先,super.foo(count)
顯式呼叫父類A
的函式。然後foo(count-1)
是一個虛擬函式呼叫,實際呼叫的是子類B
中的函式。
由於類似的行為存在歧義,因此Kotlin1.4中禁止同時使用open
和tailrec
進行修飾。
如何更新
照舊,你可以在play.kotl.in線上試用Kotlin。
- Maven, Gradle, 和npm:編譯器和標準庫版本指定為
1.3.60
。這裡檢視文件。 - IntelliJ IDEA和Android Studio:開啟Tools | Kotlin | Configure Kotlin Plugin Updates然後點選“Check for updates now”按鈕,更新Kotlin外掛到1.3.60版本。
- Eclipse:在Marketplace安裝外掛。
- 命令列編譯器:在Github release page下載最新版本。
若你在新版本中發現任何問題,歡迎在論壇或 Slack (點選獲取邀請)裡尋求幫助,或者在問題跟蹤器提交問題。
Let’s Kotlin!
其他貢獻者
我們特別感謝Steven Schäfer,他最佳化了內聯
類中的比較.
我們同樣感謝PR被合併到該版本的其他貢獻者:
- Toshiaki Kameyama
- Ivan Gavrilovic
- Mads Ager
- Mark Punzalan
- pyos
- Jake Wharton
- Yanis Batura
- ilgonmic
- Kristoffer Andersen
- Sebastian Schuberth
- Kevin Bierhoff
- scache
- keijumt
- Louis CAD
- Matthew Gharrity
- Jim Sproch
- Jim S
- Dereck Bridie
- Sascha Peilicke
- SatoShun
- Sergey Bogolepov
- Dat Trieu
- Burak Eregar
- Ty Smith
- Vladimir Krivosheev
- Alex Chmyr