在Kotlin中有幾個十分相似的標準庫函式,他們之間也有一些差異,如果使用不當可能回得到與預期相反的效果,所以我們來簡短的區分一下let、also、run、with、apply 這5個標準庫函式的區別。 Kotlin提供了這幾種標準域函式主要是為了簡化一些操作,讓程式碼看起來更加的簡潔,可讀性更好。
在最開始我們先建立一個簡單的Book類,作為例子我們來看看每種函式的不同
data class Book(var name: String, var author: String, var price: String){
fun adjust( value: Int){
price = price.plus(value)
}
}
fun main(){
}
複製程式碼
上述是一個非常簡單的Book類,包括三個屬性:書名、作者、價格。然後有一個調整價格的方法。
- let
Book("《海邊的卡夫卡》", "村上春樹", 59).let {
println(it)
it.adjust(-5) //let的引數為it,也就是自身
println(it)
}
複製程式碼
在Book類的main函式中新增上述程式碼,並且執行,結果如下:
Book(name=《海邊的卡夫卡》, author=村上春樹, price=59) Book(name=《海邊的卡夫卡》, author=村上春樹, price=54)
在上述程式碼中,我們可以看到let的引數為自身,即:block: .(T)
,將自身作為引數傳遞。
- run
如果我們要用run函式實現與let一樣的功能,應該是這樣的:
Book("《海邊的卡夫卡》", "村上春樹", 59).run {
println(this)
this.adjust(-5)
println(this)
}
複製程式碼
可以看出來,run更像是Book物件的擴充套件函式,即:block: T.()
。他是將this作為引數傳遞,在大多數情況下this可以被省略,因此我們可以更加關注內部實現。
- with
同樣的,如果要實現上述目的,我們使用with應該是這樣的:
with(Book("《海邊的卡夫卡》", "村上春樹", 59)){
println(this)
this.adjust(-5)
println(this)
}
複製程式碼
這裡要說明的一點是,with與其餘4個庫函式最大的不同就在於with不是一個擴充套件函式。with是一個普通函式,那麼如果我們在with中傳遞了一個可為空的引數時,with函式將會變成:
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)
}
複製程式碼
- also
上面我們說到了,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
對於apply函式來說,傳遞的引數是this, 返回值也是this。當然apply還有另一個作用,就是可以輕鬆的實現Builder模式(這裡我們使用另一個物件Persion):
Persion().apply{
name = "小明"
age = "13"
brithday = "2000-01-01"
}
複製程式碼