Kotlin Scope Functions (作用域函式)
Kotlin 標準函式庫提供了 5 個非常有名的函式:let, run, with, apply, also。
它們的功能非常相似:在一個物件的 Context (作用域) 中執行程式碼。
差別在於:
- 這個物件在
block裡面是用this還是it參考? - 這個函式最後回傳的是 物件本身 還是 Block 的執行結果?
這張表背起來就對了:
| 函式 | 物件參考 | 回傳值 | 主要用途 |
|---|---|---|---|
| let | it | Block 結果 | 配合 ?.let 做 Null check |
| apply | this | 物件本身 | 物件初始化與設定 |
| run | this | Block 結果 | 執行區塊並計算結果 |
| also | it | 物件本身 | 額外操作 (如 Log) |
| with | this | Block 結果 | 針對一個物件多次操作 (非 Extension) |
let
最常用來處理 Nullable 物件。
val name: String? = "Miko"
name?.let {
// 只有當 name 不是 null 時才會執行這裡
println("Name length is ${it.length}")
}
apply
最常用來設定物件初始化屬性(尤其是 Android 的 Intent 或 View)。
val person = Person().apply {
name = "Miko"
age = 18
} // 回傳設定好的 person 物件
also
適合用來做「副作用」操作,例如 Log,不影響原本流程。
val person = Person("Miko").also {
println("Create person: $it")
}
run
run 有兩種用法:
- Scope Function: 類似
apply,但是回傳的是 Block 的結果 (最後一行),而不是物件本身。 - Standard Function: 用來執行一個區塊並計算結果。
// 1. 作為 Scope Function (T.run)
val result = "Hello World".run {
// 這裡用 this
println("Original length: $length")
length + 10 // 回傳這個計算結果
}
// 2. 作為標準函式 (run { })
val calculatedValue = run {
val x = 10
val y = 20
x + y
}
with
with 不是 Extension Function,它是一個獨立的函式。
用法:with(object) { ... }。
適合用來對同一個物件進行連續操作,省去重複寫變數名稱。
val webView = WebView(context)
with(webView) {
settings.javaScriptEnabled = true
loadUrl("https://www.google.com")
}
該怎麼選?
這看起來很亂,但其實有簡單的選擇邏輯:
| 你的目的是什麼? | 我該選誰? |
|---|---|
我要做 Null Check (?.) | 用 let |
| 我要初始化/設定物件 | 用 apply |
| 我要做額外操作 (Log/Print) | 用 also |
| 我要執行運算並回傳結果 | 用 run |
| 我要對一個物件連續呼叫方法 | 用 with |