with
with
函數接收兩個參數:第一個參數可以是一個任意類型的對象,第二個參數是一個Lambda表達式。with
函數會在Lambda表達式中提供第一個參數對象的上下文,并使用Lambda表達式中的最后一行代碼作為返回值返回。示例代碼如下:
val result = with(obj) {// 這里是obj的上下文"value" // with函數的返回值
}
那么這個函數有什么作用呢?它可以在連續調用同一個對象的多個方法時讓代碼變得更加精簡,下面我們來看一個具體的例子。
比如有一個水果列表,現在我們想吃完所有水果,并將結果打印出來,就可以這樣寫:
val list = listOf("蘋果","香蕉","梨","火龍果","芭蕉","椰子")val builder = StringBuilder()builder.append("開始\n")for (fruit in list){builder.append(fruit).append("\n")}builder.append("結束\n")println(builder.toString())
仔細觀察上述代碼,你會發現我們連續調用了很多次builder
對象的方法。其實這個時候就可以考慮使用with
函數來讓代碼變得更加精簡,如下所示:
val builderWith = with(StringBuilder()) {append("開始\n")for (fruit in list) {append(fruit).append("\n")}append("結束").append("\n")toString()}println(builderWith)
這兩段代碼的執行結果是一模一樣的,但是明顯第二段代碼的寫法更加簡潔一些,這就是with
函數的作用。
run
run
函數的用法和使用場景其實和with
函數是非常類似的,只是稍微做了一些語法改動而已。首先run
函數通常不會直接調用,而是要在某個對象的基礎上調用;其次run
函數只接收一個Lambda參數,并且會在Lambda表達式中提供調用對象的上下文。其他方面和with
函數是一樣的,包括也會使用Lambda表達式中的最后一行代碼作為返回值返回。示例代碼如下:
val result = obj.run {// 這里是obj的上下文"value" // run函數的返回值
}
那么現在我們就可以使用run
函數來修改一下吃水果的這段代碼,如下所示:
val builderRun = StringBuilder().run {append("開始\n")for (fruit in list) {append(fruit).append("\n")}append("結束").append("\n")toString()}println(builderRun)
總體來說變化非常小,只是將調用with
函數并傳入StringBuilder
對象改成了調用StringBuilder
對象的run
方法,其他都沒有任何區別,這兩段代碼最終的執行結果是完全相同的。
apply
apply
函數和run
函數也是極其類似的,都要在某個對象上調用,并且只接收一個Lambda參數,也會在Lambda表達式中提供調用對象的上下文,但是apply
函數無法指定返回值,而是會自動返回調用對象本身。示例代碼如下:
val result = obj.apply {// 這里是obj的上下文
}
// result == obj
那么現在我們再使用apply
函數來修改一下吃水果的這段代碼,如下所示:
val builderApply = StringBuilder().apply {append("開始\n")for (fruit in list) {append(fruit).append("\n")}append("結束").append("\n")}println(builderApply.toString())
注意這里的代碼變化,由于apply
函數無法指定返回值,只能返回調用對象本身,因此這里的result
實際上是一個StringBuilder
對象,所以我們在最后打印的時候還要再調用它的toString()
方法才行。