Android Kotlin 的現狀和未來

petterchx發表於2021-09-09

Andrey Breslav,Kotlin 專案負責人,今天他以一個工具開發者和工具生態系統的角度來給我們介紹 Kotlin 的概況。然後他會講講未來和他們下個版本的一些資訊。


介紹 

我的名字叫 Andrey,我在  帶領著  團隊。今天我來和大家聊聊我們現在的狀態和未來的計劃。

學習材料 

這篇演講不是 Kotlin 的入門介紹。如果你想學習 Kotlin,到處都能找到學習的資源。這裡有一個。試試我們的 ,Kotlin Koans 是一組你上手這個語言的相關問題,類似於一個嵌入教程的 IDE。 我在這裡鼓勵你們學習!

現狀 

Kotlin 1.0 在 2016 年二月份釋出了。那之後我們做了許多更新:1.0.2 是我們現在的版本,我們現在正在開發 1.1 (一個功能驅動的版本,雖然我不能給你們一個確定的釋出日期)。專案的早期試用 (EAP) 會在今年夏天開始。

在本次的講稿中 (參見影片) 我們有已經使用 Kotlin 的人了 (也許沒有公開承認!)。 JetBrains 有很多的使用者,我們可能是第一個試著產品化的先鋒者。我們有超過 500 萬行的程式碼,而且在不同專案裡面產品化,從我們主要的 IDE IntelliJ 產品到伺服器端的產品 (……到每一個產品)。一些專案從開始的時候就是用的 Kotlin。其他的也跟上了。我們非常感謝每一個在它們的產品中使用 Kotlin 的人。我們還處在釋出的很早期!加入我們吧,你會發現這是一個好公司的。

而且作為一個好公司,你不會孤獨。你會有一個活躍的社群,Slack,論壇,StackOverflow,所有的人都非常願意指出你做的不對的地方,和幫助你修改你的問題。說到我們的 GitHub 專案,它是開源的,你可以加入 (我們已經有了超過 100 OSS 貢獻者!)。如果你碰到問題,我們會盡最大努力工作來服務你。如果你有關鍵的問題呢,我們會以一個 EAP build 的方式來發布,這樣你可以在它上面工作來解決問題。

KEEP 

Kotlin 演進和增強流程 (KEEP): 我們試著積累我們有的所有的設計流程,而且最大程度開放。如果你去看  你會看到現在我們給 Kotlin 1.1 準備的一些方案。你可以提供你的點子,反饋,做些修改。我們非常感謝你們:使用者用例是我們設計的動力。KEEP 是我們計劃的地方。

我們的計劃 - 開發路線 

現在我們有 1.0, 1.0.2,作為主要的版本,我們的開發分成兩條線。我們有增量的更新,1.0.2, 1.0.3,它們是相容的 (意味著語言的變化沒有 bug 修正多)。我們修正編譯器裡面的 bug;這會少量修改語法 (但是這都是為了更好)。這裡你會發現缺陷修正,效能提升,和工具功能。這裡是 IDE 演進的地方:編譯系統。

1.1 是另外一條線,這裡我們實現語法功能,它們的相容性是向後相容。1.0 也許不會相容 1.1 (因為有些功能 1.0 是不知道的)。向後相容是可以的。如果你有些老的程式碼,它們會和 1.1 一起工作正常。

這個幻燈片不意味著二進位制的相容性,因為那不用說。

工具計劃:1.0.X 

  • 我們釋出了 1.0.2,它支援 Gradle 的增量編譯 (這會使得事情加快一些)。現在,當你改變一些程式碼而且呼叫它們,然後用 Gradle 來編譯的時候,使能增量編譯標誌 (這是個實驗性的標誌,預設沒有使能),你只會有哪些真的需要編譯的程式碼重新參加編譯。整個專案沒有重新構建,只有那些改動的個別檔案或者和改動相關的檔案才會編譯。而且你會用上這個功能的;一段時間以後它不再是實驗性的了 (希望是!)。這一個重大的結構性的改變。

  • IDE 裡整合 Spring 支援。你會有一些像 IntelliJ idea 為 Java 實現的功能,但是不在 caudlen 裡。

  • 減少我們標準庫的大小。那不是標準庫因為我們的標準庫太大了 (這可能是可選擇的 jvm 語言裡面最小的了)。最近一次,我們從二進位制庫中去掉了 1500 個方法,而不改變 API。這是個相容的改動,但是現在方法少些了。如果你是安卓開發者,這對你很重要。

  • 安卓 Lint 檢查 (人們需要這個)。 IDE 會警告你,如果你做了一些安卓標準條款規定不允許的事情的話。(不是語言特定的標準)。我們會有越來越多的 Lint 檢查。

  • Jack&Jill,我們正在整合安卓最新的工具。我們修改了一些缺陷能讓 Jill 編譯 Kotlin 核心庫 (因為,沒有這些修正,它編譯不過)。

新的目標 

關於 1.1…… 我們計劃了許多的事情!

  1. Java 8/9。我們當前的目標是 Java 6:你在 Kotlin 編譯的任何東西都能在 Java 6 上執行,包括 Java 8/9 (但是它不能用 8/9 的功能)。我們在實現 Java 8 的自動生成預設方法的功能。在 Kotlin 裡,你可以實現方法和介面,但是如果你想擴充套件一個 Java 裡的介面,Java 6 是不知道那些方法是實現了的 (Java 8 可以)。我們的 Java 8 裡的 Stream API collection 也有一些問題。我們有一些 Java 8 streams 的支援庫,但是它們在 Kotlin 1.1 裡面被移除了,所以我們只支援本地編譯器了。

  2. Kotlin 的 JavaScript 後臺已經有些年頭了,但是我們降低了它的優先順序,為了使得 1.0 能夠儘快釋出。我們現在又重啟了這項工作,而且所有的語言功能都會被覆蓋。我們工作在實時模組的支援上 (amd, umd, common.js)。JavaScript 有許多公共的工具鏈 (npm, browserify, gulp, ……),而且我們會盡量支援我們能做到的最多的工具鏈。

  3. 另外一個流行的問題,我能夠在一個沒有虛擬機器的本地環境上執行 Kotlin 嗎?現在的回答是不行;至少不容易。這部分沒有任何程式碼,而且也不會在 1.1 裡面支援,但是我們正在研究這個問題,也許不久就會有相關的訊息出來。

Scripting: example.kts 

現代語言的一個必要條件就是需要成為一個指令碼語言。或多或少支援一些,雖然它沒有正式地提出來。你可以在 Kotlin 裡面寫些指令碼,檔案的副檔名是 .kts。從現在開始,你可以在檔案頭匯入任何東西而且可以寫任何的陳述和表達。它會被編譯成 Java 類,然後執行正常。

然而,你不能在一個指令碼里面定義依賴,這意味著你要麼配置自己的 class path,或者使用 jtk 和 Kotlin 的標準庫。這是我們正在工作的地方,而且你可能幫助許多其他的 Kotlin 的用法。這是一個結構性的改變。

Type Aliases 

當你打算傳遞一個函式 (比如,一個 foo 和 bar to buzz),,你最終會重複好幾遍這個函式的簽名。這是為什麼人們想用一些縮寫的機制,給這種複雜型別一個名字。

typealias Int32 = Int
typealias Predicate<T> = (T) -> Boolean

這裡是我的給 Boolean 的一個複雜型別 T,一個函式,而且我打算這麼叫它。我說 typealias Predicate<T> = (T) -> Boolean。這不是一個新的型別,它只是一個縮寫;一個簡稱。Int32 這裡就是一個 Int。它們是通用的,但是它們會幫助你縮寫你的長型別,然後使你的 API 更易讀。新型別也是人們想要的東西。它不是一個型別縮寫。它可能會在版本 1.1 裡面支援,透過值型別 (或者相關的其他東西)。你可能聽說過 Valhalla 專案 (那些對 Java 感興趣的人),這更容易。

繫結方法引用 

kotlin 語言支援反射(假設其執行平臺支援反射)。

val p: Predicate<String> = “foo”::equals
    // behaves as { x -> “foo”.equals(x) }

val c: KClass<Foo> = x.foo()::class

這兩個冒號 (type ::foo) 是我們支援的。你可以使用一個型別,然後引用它的一個成員,一個函式或者一個屬性。或者,你可以使用一個型別然後讓它成為一個類,透過這樣 Type::class。這是現在你能做的一些事情,但是在 1.1 裡面,你可以對一個物件做同樣的事情了。他能使用一個 foo (“foo” 明顯是一個串),然後它可以和另外一個串 相等,這可以是一個單一引數的函式,然後讓它的變數是可變的。這會使你能夠拿傳入的任何串和 foo 比較。這是一個部分應用,但是很有限的例子。根據我們的使用者調查,這很方便。

或多或少都工作,就像 lamda 一樣。你將可以對一個類做同樣的事情;你可以有一個類 X 成為 foo 透過宣告 ::class。

屬性增強 

如果你不知道代理屬性是什麼東西…… 谷歌它,因為它很酷。 (Ed. 注意:) 這是允許我們更好的重用程式碼的方法,Kotlin。好訊息:在 1.1 裡面我們允許本地變數也有這個屬性。現在你可以在最頂層或者一個類裡面使用 delegated properties;你也可以在一個函式里面使用它。這使能了 DSLs,而且它能在一些新的情況下幫助我們。

fun foo() {
    val lazyBar by lazy { ... }
    while (...) {
        if (...) {
            lazyBar.doBaz()
    ...
}

內嵌屬性:一些庫的技術;二進位制相容性,還是內嵌屬性更好。

val foo: Foo
    inline get() = ...
    inline set(v) { ... }

資料類的繼承 

(如果你沒有聽過資料類,學習下它們)。 (Ed. 注意: )

data class User(val name: String, val age: Int)

// automatically gets
equals() / hashCode() / toString()
copy() // val newUser = someUser.copy(name = “Jane Doe”)
componentN() // val (name, age) = someUser

Kotlin 支援這個簡單但是有用的功能,這裡你可以定義一個有兩個成員的類。它是 類的使用者,它有一個名字和一個年紀 (這些是欄位)。它可以被標識成資料,而且編譯器可以為你生成所有的事情。它會在這些值得基礎上給你一個 equals() 和 hashCode(),toString(),然後渲染它們。一個 copy() 淺複製函式來改變一個物件的名字。和一個 componentN() 函式用來析構。可以這麼說:我有一個使用者 (一個使用者是名字和年齡的值對),我宣告瞭一個本地變數,同時有名字和年齡然後分配給使用者。我同時有兩個值賦給它們兩個。

資料類很棒,但是我們不支援它們的繼承。1.1 會支援這個;你可以說,有一個密封的類,而且能夠從它開始擴充套件資料類。

sealed class C() {
    data class Example(...) : C()
}

這包含了人們在 Kotlin 裡需要的代數資料型別。這還不是 Haskell (它永遠不會是),但是它和 Haskell 和類似,和我們看到的要求的使用者用例一樣。

Lambdas 裡的解構 

myMap.forEach {
    (k, v) ->
    println(“$k => $v”)
}

一個從 N 到 串的 map 是一個值對的序列,對應著所有的鍵和值。在這個庫裡,Map 有一個 .forEach 的方法。這簡單地遍歷了所有的值對,然後你可以做所有你想做的事情。在 Kotlin 1.0 裡,一個完整的值對只能有一個變數。你可以說,forEach 有一個條目,而且可以說 (k, v) -> println(“$k => $v”)。這個 1.1 的新語法會幫你正確地解構。如果你說 K 和 V 是一對 (這意味著整個條目會構建這兩個值),然後你可以列印這兩個值。 現在我已經丟掉了我的聽眾了嗎?

我有一個黑色的螢幕 (看影片)。你不需要讀那些程式碼。你需要關心的只有括號內的縮排。這是我在谷歌搜尋 ‘callback hell’ 的圖片。這張圖片是一個典型的 JavaScript 的片段 (不僅僅是 JavaScript,其他語言也會有這個痛點)。這說明非同步計算的世界多多少少今天在許多語言中都存在。

我們想盡可能的變得非同步,因為我們喜歡把不同的事情交給不同的執行緒或者其他不同的執行方式去完成。我想讀取一個檔案的方式是:”這是我的檔案,我想讀取它。當讀完的時候,這是我的回撥函式,結束的時候呼叫它”。這太棒了;我可以呼叫一些事情,我不會被阻塞。我可以繼續工作;讀操作會完成的。但是,如果在讀完之後我想寫資料,然後另外一個讀操作發生了,每一個下步非同步呼叫會被嵌入到剛才的回撥函式中。這樣就會在回撥裡面有一個回撥又有一個回撥……然後最後我有這些縮排。如果 115 行能完成大概還行,但是有時候就不是這樣了。這是為什麼有的語言有 async/await。

非同步計算 

一些語言想寫出同樣的非同步呼叫,不阻塞在呼叫上,但是是用序列的方式。

fun loadImage(url: URL) = async {
    val bytes = await(loadBytes(url))
    bytesToImage(bytes)}

我只說了 loadBytes 然後 bytesToImage,意味著 loadBytes 應該非同步工作而且只在結束的時候才會執行 bytesToimage。這裡這個 await 關鍵字,意味著呼叫 load bytes,把其他的計算放在別處,不阻塞當前的執行緒,讓執行緒能為別人做些事情。而且,當 loadBytes 結束的時候,復活所有的計算然後執行下一行。

這是 C# 在版本五里引入的。其他的語言也採納了這個點子因為它卓有成效,而且這也是我們想涉及的東西。但是在我們看來,我們不想抄襲別人因為它不夠通用。他們有一個非同步計算,一個同步塊和一個懸掛點。 Await 意味著我們可以在這裡暫停然後再恢復。

協同 

另外我們想用協同。這是通用的。我們想在其他語言的生產塊中覆蓋 async/await/yield,但是保持最大的靈活性。我們想最終支援已有的所有非同步 API,futures,回撥,promises。而且這意味著語言不會和給定的任務框架繫結。

fun loadImage(url: URL) = async {
    val bytes = await(loadBytes(url))
    bytesToImage(bytes)
}

我們有一些 async 和 await:這些是庫的功能,不是關鍵字。這是不同的 API 確有著同樣的功能,但是更靈活。原型正在開發 (也許六月能完成),我們會採用抽象來構建這些庫和使用這些庫。

結論 

我想邀請你們來到 KEEP,稽核這些提案。提供你們的反饋,想法和用例。

原文連結:http://www.apkbus.com/blog-705730-61001.html

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/4606/viewspace-2815110/,如需轉載,請註明出處,否則將追究法律責任。

相關文章