兩個主要區別
- 上下文對象用this 還是 it
- 返回值
上下文對象用this 還是 it
this和it是作用域函數獲取對象引用的 短名稱, 兩者都提供相同的功能
使用this的情況
範圍函數: run,with,apply 使用this
在大多數情況下,this訪問接收器對象的成員時可以省略,從而使代碼更短
比如這個例子就是省略了this
data class Person(var name: String, var age: Int = 0, var city: String = "")
fun main() {
val adam = Person("Adam").apply {
age = 20 // same as this.age = 20 or adam.age = 20
city = "London"
}
}
但是不加this,就不容易區分age、city是來自內部接收器Person 還是 外部成員或功能
大家看下不容易區分的情況
data class Person(var name: String, var age: Int = 0, var city: String = "")
var otherName = "wangxueming"
fun main() {
val adam = Person("Adam").apply {
age = 20 // same as this.age = 20 or adam.age = 20
city = "London"
otherName = "wxm"
}
println("age = ${adam.age}; city = ${adam.city}; otherName = ${otherName}")
}
這裏的otherName你就不容易看出來到底是Person的變量還是外部變量。
使用it的情況
範圍函數: let,also使用it
- it相較this更爲簡潔
- 但在範圍域內this就不可用了
看範例
import kotlin.random.Random
fun writeToLog(message: String) {
println("INFO: $message")
}
fun main() {
fun getRandomInt(): Int {
return Random.nextInt(100).also {
writeToLog("getRandomInt() generated value $it")
//下面這行的this會報編譯錯誤:'this' is not defined in this context
//writeToLog("getRandomInt() generated value $this")
}
}
val i = getRandomInt()
}
it在lambda中是支持自定義名稱的
將上個範例中的getRandomInt(),從it改成value
fun getRandomInt(): Int {
return Random.nextInt(100).also { value -> {
writeToLog("getRandomInt() generated value $value")
writeToLog("getRandomInt() generated 222 value $value")
}
}
}
返回值
apply、also返回上下文對象
let、run、with返回lambda結果
返回 上下文對象
apply、also會返回 上下文對象;
但apply、also發起者是 上下文對象;
這就是個鏈式調用嘛,準確的是是對fun的鏈式調用
鏈式調用就可以這麼寫了
fun main() {
val numberList = mutableListOf<Double>()
numberList.also { println("Populating the list") }
.apply {
add(2.71)
add(3.14)
add(1.0)
}
.also { println("Sorting the list") }
.sort()
println(numberList)
}
進一步理解一下,in是上下文對象,out依舊是上下文對象
這說明 also和apply不對原先的操作造成任何影響
原來的是fun,添加了also或apply之後,返回的依舊是fun
also、apply可以理解爲對原先 fun的補充邏輯處理
我們再看一遍RandomInt的例子
import kotlin.random.Random
fun writeToLog(message: String) {
println("INFO: $message")
}
fun main() {
fun getRandomInt(): Int {
return Random.nextInt(100).also {
writeToLog("getRandomInt() generated value $it")
}
}
val i = getRandomInt()
}
添加also之後,Random.nextInt(100)不受影響,只是額外打印了一行log
這就可以動態的 給fun添加一個原先fun處理完成後的邏輯
返回lambda表達式結果
let、run、with會返回 lambda表達式結果
這就提供了 將fun計算的結果傳給下一個函數繼續計算
這是對結果的鏈接調用
看個統計末尾 字母爲e個數的範例
fun main() {
val numbers = mutableListOf("one", "two", "three")
val countEndsWithE = numbers.run {
add("four")
val Res1 = count { it.startsWith("f") }
println("Res1 = ${Res1}")
add("five")
val Res2 = count { it.startsWith("f") }
println("Res2 = ${Res2}")
println("${numbers}")
count { it.endsWith("e")&&it.startsWith("t") }
}
println("There are $countEndsWithE elements that end with e.")
}
輸出結果爲
Res1 = 1
Res2 = 2
[one, two, three, four, five]
There are 1 elements that end with e.
正如文章開頭說的,作用於表達式 只是書寫的簡化
相當於是 多行 邏輯處理的整合
每一行代碼都能依次執行,並及時的得到相應的結果
函數選擇
功能 | 對象參考 | 返回值 | 是擴展功能 | 適用情況 |
---|---|---|---|---|
let | it | Lambda結果 | 是 | 僅支持在非null對象上使用;將 表達式 像變量一樣引入到 作用域中 |
run | this | Lambda結果 | 是 | 對象配置和計算結果 |
run | – | Lambda結果 | 否:在沒有上下文對象的情況下調用 | 需要表達式的運行語句 |
with | this | Lambda結果 | 否:將上下文對象作爲參數。 | 對對象進行分組功能調用 |
apply | this | 上下文對象 | 是 | 對象配置 |
also | it | 上下文對象 | 是 | 附加功能 |