Kotlin 基礎:從 null safety 到 Standard.kt
var a: Foo? = getFoo()nif (a != null) {n print(a.foo) // 不再需要 !!n}n
而在 Swift 里,你仍然需要手動再次「!」
var a: Foo? = getFoo()nif (a != null) {n print(a!.foo) // 仍然需要 !n}n
class Bar {n var a: Foo? = getFoo()n fun bar() {n if (a != null) {n print(a.foo) // 編譯無法通過n }n }n}n
為什麼 Kotlin 此時不予編譯通過呢?因為在當前線程判斷「a != null」之後,其它線程可能又修改了「a」的值。事實上,如果是用「val」聲明的 field,此時就可以 smart cast。
而如果是「var」聲明的呢?如果你加上「!!」,變成「a!!.foo」,就可以編譯通過,但這麼做的話,你就會被抓住遊街。所以,正確的解決方式是,定義一個局部變數,這樣就確保沒有其它線程能動到它。
fun bar() {n val localA = an if (localA != null) {n print(localA.foo) // cooln }n}n
if let roomCount = john.residence?.numberOfRooms {n print("Johns residence has (roomCount) room(s).")n} else {n print("Unable to retrieve the number of rooms.")n}n
Kotlin 里,當然也可以利用「let」來寫得漂亮些。當然,Kotlin 的 DSL 能力那麼好,何必再從語法層面解決問題?
print(john.residence?.numberOfRooms?.let { "Johns residence has $it room(s)." } ?: "Unable to retrieve the number of rooms.")n
一氣呵成,不需要任何額外的語法。事實上,我實際寫代碼時,也經常會「foo?.let { … }」這麼用。
上面語句的核心就是「let」。和 Swift 不同,Kotlin 里的「let」不過只是一個普通的函數而已。事實上,很多 Kotlin 教程都不會提及標準庫里這幾個很贊的函數。它們實現得非常簡單,但卻可以作為良好 Kotlin 代碼的典範:public inline fun <T, R> T.run(block: T.() -> R): R = block()npublic inline fun <T, R> with(receiver: T, block: T.() -> R): R = receiver.block()npublic inline fun <T> T.apply(block: T.() -> Unit): T { block(); return this }npublic inline fun <T> T.also(block: (T) -> Unit): T { block(this); return this }npublic inline fun <T, R> T.let(block: (T) -> R): R = block(this)npublic inline fun <T> T.takeIf(predicate: (T) -> Boolean): T? = if (predicate(this)) this else nulln
例如某個方法,在計算出返回值後,還需要做一些清理,之前你可能:
fun foo(): Int {n val resource = getResource()n val retVal = resource.calculate()n resource.cleanUp()n return retValn}n
fun foo() = getResource().run { calculate().also { cleanUp() } }n
標準庫里的這幾個方法僅僅是最最常用和最簡單的對控制語句的補充。其實還有很多這樣的擴展方法可以用,例如 funKTionale 裡面的函數,都很棒呢。
推薦閱讀:
※#Kotlin# 一年の使用報告 - 類型設計
※Kotlin 終於成為了 Android 的官方支持語言
※#Kotlin# Activity 之朝花夕拾
TAG:Kotlin |