一:概念
Kotlin 標準庫包含幾個函數,它們的唯一目的是在對象的上下文中執行代碼塊。當對一個對象調用這樣的函數並提供一個 lambda 表達式時,它會形成一個臨時作用域。在此作用域中,可以訪問該對象而無需其名稱。這些函數稱爲作用域函數。共有以下五種:let
、run
、with
、apply
以及 also
。
這些函數基本上做了同樣的事情:在一個對象上執行一個代碼塊。不同的是這個對象在塊中如何使用,以及整個表達式的結果是什麼。
先來看下如果不用作用域函數,我們平常是怎麼在進行處理代碼的。
val alice = PersonMen("Alice", 20, "Amsterdam")
alice.age=16
alice.gj="Ydl"
通過作用域函數let看下是怎麼調用的:
PersonMen("Alice", 20, "Amsterdam").let {
it.age=30
it.gj="London"
}
可見使用了let函數,形成一個臨時的作用域。在此作用域中,可以訪問該對象而無需其名稱。
二:5個作用域函數的區別和相處
以下的表格是對五個作用域函數的對比
作用域函數 | 上下文對象 | 返回結果類型 | 是否能單獨使用 |
---|---|---|---|
let | it(可自定義) | lambda表達式的最後一行是返回值 | 否 |
also | it(可自定義) | T的類型(上下文對象) | 否 |
run | this(可隱式地訪問對象) | lambda表達式的最後一行是返回值 | 否 |
apply | this(可隱式地訪問對象) | T的類型(上下文對象) | 否 |
with | this(可隱式地訪問對象) | lambda表達式的最後一行是返回值 | 是 |
1:上下文對象
var str: String= "Hello"
str.let {
println("let() called on $it")
}
str.also {
println("also() called on $it")
}
str.run {
println("run() called on $this")
}
str.apply {
println("apply() called on $this")
}
with(str) {
println("with() called on $this")
}
輸出結果
let() called on Hello
also() called on Hello
run() called on Hello
apply() called on Hello
with() called on Hello
- this可隱式地訪問對象,it不能
str.let {
it.length
}
str.run {
this.length
length
}
從以上代碼可知,this省略也可以直接調用length,但是如果it省略直接寫 length ,代碼是會報錯
- it作爲上下文可進行自定義這個上下文的名字
str.let {value->
value.length
}
代碼中定義value爲上下文,但是this則不可以
2:返回結果類型
var list: MutableList<String> = mutableListOf<String>()
list.add("b")
var letResult = list.let {
it.add("a")
}
println("let() called on $letResult")
println("let() called on $list")
結果:
let() called on true
let() called on [b, a]
可以看出let函數返回結果是:lambda表達式的最後一行的值
換成also函數:
var list: MutableList<String> = mutableListOf<String>()
list.add("b")
var letResult = list.also {
it.add("a")
}
println("also() called on $letResult")
println("also() called on $list")
輸出結果:
also() called on [b, a]
also() called on [b, a]
可以看出also函數返回結果是:T的類型(上下文對象)
3.是否能單獨使用
這個在我的理解是是否一定要跟在"."的後面,這樣就限制了函數的使用位置,五種函數中不同的是with函數,with
可以理解爲“對於這個對象,執行以下操作。”
with(str) {
println("with() called on $this")
}
三:函數選擇
以下是根據預期目的選擇作用域函數的簡短指南:
- 對一個非空(non-null)對象執行 lambda 表達式:
let
- 將表達式作爲變量引入爲局部作用域中:
let
- 對象配置:
apply
- 對象配置並且計算結果:
run
- 在需要表達式的地方運行語句:非擴展的
run
- 附加效果:
also
- 一個對象的一組函數調用:
with
不同函數的使用場景存在重疊,你可以根據項目或團隊中使用的特定約定選擇函數。
儘管作用域函數是使代碼更簡潔的一種方法,但請避免過度使用它們:這會降低代碼的可讀性並可能導致錯誤。避免嵌套作用域函數,同時鏈式調用它們時要小心:此時很容易對當前上下文對象及 this
或 it
的值感到困惑。