Kotlin基礎篇——從型別系統開始

万俟霜風發表於2018-03-03

Kotlin 系列 學習筆記——第一篇

對於一門靜態程式語言,其型別系統中隱藏了很多設計思路。 Kotlin 這門需要跟 Java 對比學習的語言就更能體現這一點。把型別系統當做 Java 轉 Kotlin 的第一站對後續的學習還挺有幫助的,要是沒學過 Java 的話……應該也不會想學 Kotlin 吧。

前提:建立變數

由於型別推導系統的存在,Kotlin 中建立變數並不都需要宣告型別,只要能推匯出就好。而為了更好的支援函數語言程式設計,Kotlin 中明確區分了可變變數(variable)和不可變變數(value),分別用 varval 來建立。

Java 中可以用 final 修飾符表示不可變變數,可能因為寫法比較麻煩,除了必要的地方很少出現不可變變數。Kotlin 中兩種方式一樣好寫,就會引導人從場景方面考慮 valvar 哪個更合適。為了更好的可讀性,應該儘可能減少 var 的使用,因為可以隨意改變意味著每次該變數出現都需要考慮當時的值是什麼,而且經常出現不可預測的值。

Java 的基本資料型別

在 Java 中,基本資料型別和引用資料型別是明確區分的,基本資料型別是 Java 中脫離了物件導向的一部分,也因此提高了執行效率。而基本資料型別又都對應著一個包裝型別(屬於引用資料型別),提供了物件導向的思路。

在 Kotlin 中就不存在這種基本資料型別了,看起來像是隻保留了包裝型別。實際上在編譯過程中,只有真正需要使用包裝型別的才會編譯成引用資料型別,並不會影響程式碼執行的效率。

val a: Int = 128
val b: Int = 666

val sum = a + b

// 這種純粹的數字編譯後跟 Java 中的 int 是一樣的
複製程式碼

特殊型別

特殊的資料型別有三個:UnitAnyNothing

Unit:意義上相當於 Java 中的 void,定義函式不需要返回值的時候,就可以返回Unit(省略不寫就預設返回Unit了)。實際上 Unit 和 void 還是有區別的,Unit 是一種真實型別,它有唯一的 隱式 取值 Unit。《Kotlin實戰》中寫了這種設計在泛型中的應用和優勢,

Any:Any 相當於 Java 中的 Object 類,是所有類的爸爸。但需要注意的是 Any 只有 toStringequalshashCode函式而不能使用 waitnotify方法,如果有需要的話可以把 Any 轉換為 Java 的 Object 類再操作。

Nothing:這是一個函式的返回值型別,只在函式宣告的時候會用到,表示這個函式不會 return。比如一定會丟擲異常或者一定是死迴圈的函式。雖然不是強制的,但知道不會return任何內容對型別推導是有意義的:

Kotlin基礎篇——從型別系統開始

這裡如果 error 函式的返回值不寫明 Nothing 會被認為是 Unit ,user 的型別就會被推導為 Any ,因為 ?: 前後的型別不一致。

可空型別 (?)

空安全是 Kotlin 的巨大優勢之一,有效減少 NPE 也是很多人選擇 Kotlin 的原因。空安全的核心就是對型別是否可空的區分,在 Java 中,String 型別的取值可能是 String 或 null,於是每次呼叫 String 的方法時都可能發生 NPE。這看起來並不合理,因為 null 值只能用來比較而沒有 String 的特性,卻披著 String 的外皮,還要在執行時才告訴我他不是 String。

Kotlin 用型別 + ? 來表示可空型別,有一種對此型別有疑問的感覺,還挺容易接受的。直觀點表示:

String? = String + null

不可空型別無法被賦值為 null ,在編譯期就能處理掉一大部分的 NPE 了。

不可空型別

除了定義變數,可空型別呼叫函式時也要用到 ?

a?.fun() = if(a != null){ a.fun() }

比起 Java 中層出不窮的非空判斷,這樣的寫法優勢很大,尤其是在巢狀的縮排裡面,層次越少可讀性越強。如果很確定該型別是非空的,或者需要看到這個 NPE (不會有人想看吧…),可以使用 !!. 強制呼叫函式。Kotlin 用了兩個感嘆號來描述這種行為,表明程式碼中最好不要出現這種寫法。

Java 中的 if(a != null) 還可能有 else 的處理,在 Kotlin 的簡化寫法中可以通過 ?: 可以實現。a?:b的含義是當 a 為空時,取 b。a?.fun() 在 a 為 null 的情況下整個表示式的值為 null,結合起來就是這樣的:result = a?.fun()?:b

這一行的程式碼的表現力很強,簡直是多重巢狀的救星。

簡化防空判斷

還有一種情況,就是函式接受的引數為不可空型別,而你需要對一個可空型別的資料做判斷,除了用 if 判斷,還可以使用 let 函式。let 函式的原理就等寫到函式的時候再深入,這裡只說怎麼用,下面的兩種寫法是等價的:

let函式

集合的可變性

集合系統是比較複雜的,Kotlin 並沒有完全實現一套自己的集合系統,而是在 Java 集合的基礎上進行了擴充套件。這樣可以和 Java 有更好的互操作性,同時也能比 Java 集合更加好用。集合的內容很多,這裡只說一點:不可變集合。

Java 中的集合基礎是 Collection 介面,其中包含add, removeclear等方法,即所有的集合都是可變的。Kotlin 中新增了不可變集合的概念,就相當於增加了一些型別。在建立集合的時候也需要想清楚是否需要可變性,以選擇合適的集合型別。

亂入一個充滿靈性的插圖:

Kotlin基礎篇——從型別系統開始

可以看出 List 是不可變的,ArrayList 是可變的:

Kotlin基礎篇——從型別系統開始

Kotlin 的第一篇學習筆記就是這些內容了,最初總想著記得詳細一些,但筆記畢竟還不是教程,我也的確沒有做教程的水平。這種筆記更適合在有一定基礎的情況下閱讀,利用碎片時間積累更多知識,如果有人覺得讀完文章有所收穫就再好不過了。

學習資料還是推薦官方文件以及《Kotlin實戰》,相關的程式碼實在太簡單了,就不上傳 Github 了。最近工作比較忙,下一篇隨緣吧……(?點贊評論可以增加緣分值哦)

相關文章