Kotlin基礎知識(十)——帶接受者的lambda:「with」與「apply」

1、「with」函數

  • 示例一:構建字母表
// 定義
fun alphabet(): String {
    val result = StringBuilder()
    for(letter in 'A' .. 'Z') {
        result.append(letter)
    }
    result.append("\nNow I know the alphabet!")
    return result.toString()
}

// 測試
>>> println(alphabet())
ABCDEFGHIJKLMNOPQRSTUVWXYZ
Now I know the alphabet!
複製代碼

上述例子中,調用result實例上好幾個不一樣的方法,並且每次調用都要重複result這個名稱。若實例名比較長,就比較糟糕!markdown

  • 使用***with***構造字母表
fun alphabet(): String {
    val stringBuilder = StringBuilder()
    // 指定接受者的值,你會調用它的方法
    return with(stringBuilder) {
        for(letter in 'A' .. 'Z') {
            // 經過顯式的「this」來調用接受者值的方法
            this.append(letter)
        }
        // 省略「this」也能夠調用方法
        append("\nNow I know the alphabet!")
        // 從lambda返回值
        this.toString()
    }
}
複製代碼

with結構看起來像是一種特殊的語法結構,但它其實是一個接受兩個參數的函數:這個例子中兩個參數分別是stringBuilder和一個lambda。這裏利用了把lambda放在括號外的約定,這樣整個調用看起來就像是內建的語言功能。固然也能夠把它寫成*with(stringBuilder, { ... })***,但可讀性就會差不少。app

with函數把它的第一個參數轉換成做爲第二個參數傳給它的lambda的接受者。能夠顯示地經過this引用來訪問這個接受者。或者,按照慣例,能夠省略this引用,不用任何限定符直接訪問這個值的方法和屬性。函數

  • 重構:使用with和一個表達式函數體來構建字母表
fun alphabet() = with(StringBuilder()) {
    for(letter in 'A' .. 'Z') {
        append(letter)
    }
    append("\nNow I know the alphabet!")
    toString()
}
複製代碼

如今這個函數只返回一個表達式,因此使用表達式函數體語法重寫了它。能夠建立一個新的StringBuilder實例直接看成實參傳給這個函數,而後在lambda中不須要顯示的this就能夠引用這個實例。測試

注意with返回的值是執行lambda代碼的結果,該結果就是lambda中的最後一個表達式(的值)**。ui

2、「apply」函數

apply*函數幾乎和with函數如出一轍,惟一的區別**apply始終會返回做爲實參傳遞給它的對象*(換句話說,接受者對象)。this

  • 使用apply構建字母表
fun alphabet() = StringBuilder().apply {
    for(letter in 'A' .. 'Z')
        append(letter)
    append("\nNow I know the alphabet!")
}.toString()
複製代碼

***apply被聲明成一個擴展函數。它的接受者變成了做爲實參的lambda的接受者。執行apply***的結果是StringBuilder,因此接下來你能夠調用toString把它轉換成String。spa

許多狀況下***apply***都頗有效:code

  • 建立一個對象實例並須要用正確的方式初始化它的一些屬性時。在Java中,這一般是經過另一個單獨的Builder對象來完成的;而在Kotlin中,能夠在任何對象上使用***apply***,完成不須要任何來自自定義該對象的哭的特殊支持。
fun createViewWithCustomAttributes(context: Context) =
        TextView(context).apply { 
            text = "Sample Text"
            textSize = 20.0F
            setPadding(10, 0, 0, 0)
        }
複製代碼
相關文章
相關標籤/搜索