【譯】Kotlin 類型層級結構一覽

作者 原文
Nat Pryce A Whirlwind Tour of the Kotlin Type Hierarchy

Kotlin 有大量優(yōu)秀的語言文檔教程役耕。但是我沒有找到任何描述 Kotlin 類型層級結構(type hierarchy)是如何組成的文章。那真是太可惜了萝映,因為我覺得這個類型系統(tǒng)很棒1交惯。

關于 Kotlin 的類型層級結構只有很少的幾條規(guī)則需要了解,這些規(guī)則一致和可預測地結合在一起望迎。得益于這些規(guī)則,Kotlin 可以提供一些有用的語言特性——空安全性(null safety)凌外、多態(tài)性(polymorphism)辩尊、不可達代碼分析(unreachable code analysis),而不需要在編譯器和 IDE 中使用一些手段進行特殊處理康辑。

頂層類型

Kotlin 中所有類型被組織成父類型/子類型(supertype/subtype)關系的層級結構摄欲。

這個層級結構的頂層Any 類型。例如 StringInt 都是 Any 的子類型疮薇。

Any 相當于 Java 的 Object 類型胸墙。與 Java 不同的是 Kotlin 不區(qū)分原始類型(primitive type)和其它的類型。它們都是同一類型層級結構的一部分按咒。

如果定義了一個沒有指定父類的類型迟隅,則該類型將是 Any 的直接子類型。

class Fruit(val ripeness: Double)

如果你為定義的類型指定了父類励七,則該父類將是新類型的直接父類型智袭,并且新類型的最終祖先為 Any

abstract class Fruit(val ripeness: Double)
class Banana(ripeness: Double, val bendiness: Double): 
    Fruit(ripeness)
class Peach(ripeness: Double, val fuzziness: Double): 
    Fruit(ripeness)

如果你的類型實現(xiàn)了多個接口呀伙,那么它將具有多個直接的父類型补履,而 Any 同樣是最終的祖先。

interface ICanGoInASalad
interface ICanBeSunDried

class Tomato(ripeness: Double): 
    Fruit(ripeness), 
    ICanGoInASalad, 
    ICanBeSunDried 

Kotlin 的類型檢查器實施父類型/子類型關系剿另。

例如你可以將子類型值存儲到父類型變量中:

var f: Fruit = Banana(bendiness=0.5)
f = Peach(fuzziness=0.8)

但是你不能將父類型值存儲到子類型變量中:

val b = Banana(bendiness=0.5)
val f: Fruit = b
val b2: Banana = f
// Error: Type mismatch: inferred type is Fruit but Banana was expected 

可空類型(Nullable Types)

與 Java 不同箫锤,Kotlin 區(qū)分非空(non-null)和可空(nullable)類型。到目前為止雨女,我們看到的類型都是非空類型谚攒,Kotlin 不允許 null 作為這些類型的值。訪問非空類型的變量將永遠不會拋出空指針異常氛堕。

類型檢查器拒絕嘗試在非空類型上使用 null 或可空類型的代碼馏臭。

例如:

var s : String = null
// Error: Null can not be a value of a non-null type String

如果一個變量存儲的值可能為空,則需要使用與值對應的可空類型讼稚。例如 String? 類型是與 String 對應的可空類型括儒,String? 類型的變量可以為任意的 String 值或者 null

var s : String? = null
s = "foo"
s = null
s = bar

類型檢查器能確保你在使用一個可空類型的變量前不會忘記檢查是否非空锐想。Kotlin 提供了一些操作符用以便捷的使用可空類型帮寻。有關例子請參閱 Kotlin 語言文檔的 Null Safety 部分

可空類型具有與對應的非空類型相同的層級結構赠摇。例如 StringAny 的子類型固逗,則 String?Any? 的子類型浅蚪;BananaFruit 的子類型,則 Banana?Fruit? 的子類型烫罩。

Any 是非空類型層級結構的頂層惜傲,Any? 則是可空類型層級結構的頂層。因為 Any?Any 的父類型贝攒,所以 Any? 是 Kotlin 類型層級結構的最頂端盗誊。

非空類型是其對應可空類型的子類型。例如 String 作為 Any 的子類型饿这,同時也是 String? 的子類型浊伙。

這就是為什么可以將非空的 String 值存儲到可空的 String? 變量中,但是不能將可空的 String? 值存儲到非空的 String 變量中长捧。Kotlin 的空安全性不是由特殊規(guī)則實施的嚣鄙,而是可空類型與非空類型之間父類型/子類型關系的結果。

這一規(guī)則也適用于自定義的類型串结。

Unit

Kotlin 是一種表達式導向的語言哑子,所有流程控制語句都是表達式。它沒有 Java 和 C 中的 void 函數(shù)肌割,函數(shù)總是會返回一個值卧蜓。通常我們?yōu)榱烁弊饔茫╯ide effect)而調用的那些沒有實際計算任何東西的函數(shù),將會返回 Unit——一種只有一個值的類型把敞。

大多數(shù)情況下弥奸,你不需要明確指定 Unit 作為返回類型或從函數(shù)返回 Unit。如果編寫的函數(shù)具有塊代碼體奋早,并且不指定返回類型盛霎,則編譯器會將其視為返回 Unit 類型,否則編譯器會使用推斷的類型耽装。

fun example() {
    println("block body and no explicit return type, so returns Unit")
}

val u: Unit = example()

Unit 并沒什么特別之處愤炸。就像任何其他類型,它是 Any 的子類型掉奄,而 Unit?Any? 的子類型规个。

Unit? 類型是一個奇怪的特殊例子,這是 Kotlin 的類型系統(tǒng)一致性的結果姓建。Unit? 類型只有兩個值:Unit 單例和 null诞仓。我從來沒有發(fā)現(xiàn)需要明確使用 Unit? 類型的地方,但是在類型系統(tǒng)中沒有特殊的 void 這一事實速兔,使得處理各種函數(shù)泛型變得更加容易狂芋。

Nothing

在 Kotlin 類型層級結構的最底層是 Nothing 類型。

顧名思義憨栽,Nothing 是沒有實例的類型。Nothing 類型的表達式不會產生任何值。

注意 UnitNothing 之間的區(qū)別屑柔,對 Unit 類型的表達式求值將返回 Unit 的單例屡萤,而對 Nothing 類型的表達式求值則永遠都不會返回。

這意味著任何類型為 Nothing 的表達式之后的所有代碼都是無法得到執(zhí)行的(unreachable code)掸宛,編譯器和 IDE 會向你發(fā)出警告死陆。

什么樣的表達式類型為 Nothing 呢?流程控制中與跳轉相關的表達式唧瘾。

例如 throw 關鍵字打斷表達式的計算措译,并從函數(shù)中拋出異常。因此 throw 就是 Nothing 類型的表達式饰序。

通過將 Nothing 作為所有類型的子類型领虹,類型系統(tǒng)允許程序中的任何表達求值失敗。這是真實世界的模型求豫,例如 JVM 在計算表達式時內存不足塌衰,或者是有人拔掉了計算機的電源插頭。這也意味著我們可以從任何表達式中拋出異常蝠嘉。

fun formatCell(value: Double): String =
    if (value.isNaN()) 
        throw IllegalArgumentException("$value is not a number") 
    else 
        value.toString()

你可能會驚奇地發(fā)現(xiàn)最疆,return 語句的類型也為 Nothingreturn 是一個流程控制語句蚤告,它立即從函數(shù)中返回一個值努酸,打斷其所在表達式的求值。

fun formatCellRounded(value: Double): String =
    val rounded: Long = if (value.isNaN()) return "#ERROR" else Math.round(value)
    rounded.toString()

進入無限循環(huán)或殺死當前進程的函數(shù)返回類型也為 Nothing杜恰。例如 Kotlin 標準庫將 exitProcess 函數(shù)聲明為:

fun exitProcess(status: Int): Nothing

如果你編寫自己的返回 Nothing 的函數(shù)获诈,編譯器同樣能檢查出調用函數(shù)后無法得到執(zhí)行的代碼,就像使用語言本身的流程控制語句一樣箫章。

inline fun forever(action: ()->Unit): Nothing {
    while(true) action()
}

fun example() {
    forever {
        println("doing...")
    }
    println("done") // Warning: Unreachable code
}

與空安全一樣烙荷,不可達代碼分析是類型系統(tǒng)的一個特性。無需像 Java 一樣在編譯器和 IDE 中使用一些手段進行特殊處理檬寂。

可空的 Nothing?

Nothing 像任何其他類型一樣终抽,如果允許其為空則可以得到對應的類型 Nothing?Nothing? 只能包含一個值:null桶至。事實上 Nothing? 就是 null 的類型昼伴。

Nothing? 是所有可空類型的最終子類型,所以我們可以使用 null 作為任何可空類型的值镣屹。

結論

當你同時考慮這一切時圃郊,可能會覺得 Kotlin 的整個類型層級結構相當復雜。

但不要害怕女蜈!

我希望這篇文章能證明 Kotlin 有一個簡單而一致的類型系統(tǒng)持舆。只有很少的幾條規(guī)則需要了解:這是一個父類型/子類型關系的層級結構色瘩,而 Any? 在頂層,Nothing 在底層逸寓,以及非空類型是對應可空類型的子類型居兆。就這么多了,沒有其它特殊規(guī)則竹伸。一些有用語言特性泥栖,如空安全性、面向對象多態(tài)性勋篓、不可達代碼分析都是由這些簡單吧享,可預測的規(guī)則引起的。得益于這種一致性譬嚣,Kotlin 的類型檢查器是一個強有力的工具钢颂,可以幫助你編寫簡潔正確的程序。


<a id="neat">1.</a> “很棒(neat)” 的意思是 “優(yōu)雅巧妙高效”孤荣,而不是凱文 · 科斯特納在麥當娜的舞臺上表現(xiàn)出的含義<a id="neat"> </a>

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末甸陌,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子盐股,更是在濱河造成了極大的恐慌钱豁,老刑警劉巖,帶你破解...
    沈念sama閱讀 212,383評論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件疯汁,死亡現(xiàn)場離奇詭異牲尺,居然都是意外死亡,警方通過查閱死者的電腦和手機幌蚊,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,522評論 3 385
  • 文/潘曉璐 我一進店門谤碳,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人溢豆,你說我怎么就攤上這事蜒简。” “怎么了漩仙?”我有些...
    開封第一講書人閱讀 157,852評論 0 348
  • 文/不壞的土叔 我叫張陵搓茬,是天一觀的道長。 經常有香客問我队他,道長卷仑,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,621評論 1 284
  • 正文 為了忘掉前任麸折,我火速辦了婚禮锡凝,結果婚禮上,老公的妹妹穿的比我還像新娘垢啼。我一直安慰自己窜锯,他們只是感情好张肾,可當我...
    茶點故事閱讀 65,741評論 6 386
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著衬浑,像睡著了一般捌浩。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上工秩,一...
    開封第一講書人閱讀 49,929評論 1 290
  • 那天,我揣著相機與錄音进统,去河邊找鬼助币。 笑死,一個胖子當著我的面吹牛螟碎,可吹牛的內容都是我干的眉菱。 我是一名探鬼主播,決...
    沈念sama閱讀 39,076評論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼掉分,長吁一口氣:“原來是場噩夢啊……” “哼俭缓!你這毒婦竟也來了?” 一聲冷哼從身側響起酥郭,我...
    開封第一講書人閱讀 37,803評論 0 268
  • 序言:老撾萬榮一對情侶失蹤华坦,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后不从,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體惜姐,經...
    沈念sama閱讀 44,265評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 36,582評論 2 327
  • 正文 我和宋清朗相戀三年椿息,在試婚紗的時候發(fā)現(xiàn)自己被綠了歹袁。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,716評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡寝优,死狀恐怖条舔,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情乏矾,我是刑警寧澤孟抗,帶...
    沈念sama閱讀 34,395評論 4 333
  • 正文 年R本政府宣布,位于F島的核電站妻熊,受9級特大地震影響夸浅,放射性物質發(fā)生泄漏。R本人自食惡果不足惜扔役,卻給世界環(huán)境...
    茶點故事閱讀 40,039評論 3 316
  • 文/蒙蒙 一帆喇、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧亿胸,春花似錦坯钦、人聲如沸预皇。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,798評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽吟温。三九已至,卻和暖如春突颊,著一層夾襖步出監(jiān)牢的瞬間鲁豪,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,027評論 1 266
  • 我被黑心中介騙來泰國打工律秃, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留爬橡,地道東北人。 一個月前我還...
    沈念sama閱讀 46,488評論 2 361
  • 正文 我出身青樓棒动,卻偏偏與公主長得像糙申,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子船惨,可洞房花燭夜當晚...
    茶點故事閱讀 43,612評論 2 350

推薦閱讀更多精彩內容