kotlin語法之將函數做爲參數

一個setOnClickListener的錯誤

寫了個demo,點擊事件離奇的不生效。html

開始實在是看不出有什麼問題,錯誤代碼以下:閉包

findViewById<Button>(R.id.btn).setOnClickListener {
    View.OnClickListener {
        ...
    }
}
複製代碼

運行不報錯,就是不觸發OnClickListener中的代碼。app

那麼正確的寫法應該是怎樣呢?ide

以下所示:函數

// 寫法1:OnClickListener寫法
findViewById<Button>(R.id.btn).setOnClickListener(
        View.OnClickListener {
            ...
        }
)
複製代碼

或者這樣:spa

// 寫法2:閉包寫法
findViewById<Button>(R.id.btn).setOnClickListener {
    ...
}
複製代碼

爲何那個錯誤的寫法不報錯可是卻不能正確運行呢?.net

由於錯誤的寫法其實是在寫法2的閉包裏面又聲明瞭一個OnClickListener,僅僅聲明listener固然不能調用裏面的代碼了。code

將函數做爲參數傳遞

爲何setOnClickListener有兩種寫法呢?htm

實際上這裏setOnClickListener這個方法有兩個重載:對象

// 參數是OnClickListener對象
fun setOnClickListener(l: View.OnClickListener?)
// 參數是閉包
fun setOnClickListener(l: (v: View) -> Unit)
複製代碼

由於有兩個重載方法,setOnClickListener才能夠有兩種寫法。

所謂閉包:

在計算機科學中,閉包(英語:Closure),又稱詞法閉包(Lexical Closure)或函數閉包(function closures),是引用了自由變量的函數。這個被引用的自由變量將和這個函數一同存在,即便已經離開了創造它的環境也不例外。

kotlin中的閉包通常稱爲lambda表達式,詳細內容能夠查看:

高階函數與 lambda 表達式

咱們這裏只看將函數做爲參數傳遞的用法。

由於閉包這一特性的存在,上面setOnClickListener才能夠不使用傳統的OnClickListener, 下面咱們本身定義一個簡單的例子來講明。

傳統寫法:

// 聲明listener
interface TestListener {
    fun test()
}

// 聲明使用listener做爲參數的方法
private fun setListener(listener: TestListener) {
    // 調用listener的test方法
   listener.test()
}

// 方法中使用
fun main(){
    setListener(object : TestListener {
        override fun test() {
            Log.i("test_tag", "test Listener")
        }
    })
}
複製代碼

閉包寫法:

// 聲明方法
private fun setListener(listener: () -> Unit) {
    // 調用傳入的方法
    listener()
}

// 方法中使用
fun main(){
    setListener { Log.i("test_tag", "test unit") }
}
複製代碼

明顯簡化了許多,不再須要經過聲明接口設置監聽了。

須要額外說明將函數做爲參數傳遞使用的幾種變種:

帶參數的閉包:

// 帶參數
private fun setListener(l: (c: Context) -> Unit) {
    l(applicationContext)
}
// 使用,只有一個參數時,能夠用it代替傳入的參數
setListener { Toast.makeText(it, "test param", Toast.LENGTH_SHORT).show() }
複製代碼

帶參數且有返回值:

private fun setListener(l: (c: Context) -> Boolean) {
    val b = l(applicationContext)
    Toast.makeText(applicationContext, if (b) "當前時間是偶數" else "當前時間是奇數", Toast.LENGTH_SHORT).show()
}

// 使用,只有一個參數時,能夠用it代替傳入的參數
setListener {
    Toast.makeText(it, "test param", Toast.LENGTH_SHORT).show()
    // 當前時間是不是偶數
    System.currentTimeMillis() % 2 == 0L
}
複製代碼
相關文章
相關標籤/搜索