在Kotlin中有幾個十分類似的標準庫函數,他們之間也有一些差別,若是使用不當可能回獲得與預期相反的效果,因此咱們來簡短的區分一下let、also、run、with、apply 這5個標準庫函數的區別。 Kotlin提供了這幾種標準域函數主要是爲了簡化一些操做,讓代碼看起來更加的簡潔,可讀性更好。app
在最開始咱們先建立一個簡單的Book類,做爲例子咱們來看看每種函數的不一樣函數
data class Book(var name: String, var author: String, var price: String){
fun adjust( value: Int){
price = price.plus(value)
}
}
fun main(){
}
複製代碼
上述是一個很是簡單的Book類,包括三個屬性:書名、做者、價格。而後有一個調整價格的方法。ui
Book("《海邊的卡夫卡》", "村上春樹", 59).let {
println(it)
it.adjust(-5) //let的參數爲it,也就是自身
println(it)
}
複製代碼
在Book類的main函數中添加上述代碼,而且運行,結果以下:this
Book(name=《海邊的卡夫卡》, author=村上春樹, price=59) Book(name=《海邊的卡夫卡》, author=村上春樹, price=54)spa
在上述代碼中,咱們能夠看到let的參數爲自身,即:block: .(T)
,將自身做爲參數傳遞。code
若是咱們要用run函數實現與let同樣的功能,應該是這樣的:對象
Book("《海邊的卡夫卡》", "村上春樹", 59).run {
println(this)
this.adjust(-5)
println(this)
}
複製代碼
能夠看出來,run更像是Book對象的擴展函數,即:block: T.()
。他是將this做爲參數傳遞,在大多數狀況下this能夠被省略,所以咱們能夠更加關注內部實現。string
一樣的,若是要實現上述目的,咱們使用with應該是這樣的:it
with(Book("《海邊的卡夫卡》", "村上春樹", 59)){
println(this)
this.adjust(-5)
println(this)
}
複製代碼
這裏要說明的一點是,with與其他4個庫函數最大的不一樣就在於with不是一個擴展函數。with是一個普通函數,那麼若是咱們在with中傳遞了一個可爲空的參數時,with函數將會變成:io
val book: Book? = Book("《海邊的卡夫卡》", "村上春樹", 59)
with(book){
println(this)
this!!.adjust(-5) //將空判斷放在了with方法內部
println(this)
}
複製代碼
能夠看到咱們是將空判斷放在了with內部,顯然這樣不是一個很是好的實現,若是咱們使用run,就能夠很方便的解決這個問題:
val book: Book? = Book("《海邊的卡夫卡》", "村上春樹", 59)
book?.run{
println(this)
this.adjust(-5)
println(this)
}
複製代碼
上面咱們說到了,let與run的區別就在於傳遞的參數不一樣,那麼let與also的區別就在於返回值的不一樣,他們的參數都是it,可是let返回的是lamda表達式的結果。而also返回的是上下文,即:this。 咱們看一下下面的代碼。
Book("《海邊的卡夫卡》", "村上春樹", 59)
.let {
println(it)
it.adjust(-5)
it //由於adjust()方法沒有返回值,咱們須要將調整價格後的Book對象做爲lamda表達式的返回值返回
}
.let {
print(it)
}
Book("《海邊的卡夫卡》", "村上春樹", 59)
.also {
println(it)
it.adjust(-5) // 因爲also直接返回當前對象,因此咱們不用再提供返回值
}
.let {
print(it)
}
複製代碼
上述兩段代碼都輸出:
Book(name=《海邊的卡夫卡》, author=村上春樹, price=59) Book(name=《海邊的卡夫卡》, author=村上春樹, price=54)
若是咱們將第一段代碼中的第一個let{}中最後一個it返回值去掉,則會輸出:
Book(name=《海邊的卡夫卡》, author=村上春樹, price=59)
Kotlin Unit
能夠看到,let輸出的是lamda表達式的值,而also的返回值是this. 經過also與let的配合,咱們能夠寫出一些可讀性更強的鏈式調用的語句。
對於apply函數來講,傳遞的參數是this, 返回值也是this。固然apply還有另外一個做用,就是能夠輕鬆的實現Builder模式(這裏咱們使用另外一個對象Persion):
Persion().apply{
name = "小明"
age = "13"
brithday = "2000-01-01"
}
複製代碼