Kotlin 常見內聯擴充套件函式的使用

Knight_Davion發表於2017-12-22

Kotlin一個強大之處就在於它的擴充套件函式,巧妙的運用這些擴充套件函式可以讓你寫出的程式碼更加優雅,閱讀起來更加流暢,下面總結了在開發中經常用到的一些內聯擴充套件函式。經常有小夥伴搞不懂with,run,apply等等這些函式該怎麼用,在哪裡用,我的建議是先記住每個函式的功能(無非就是它需要什麼引數?返回值是什麼?)記住這兩點再根據實際開發中的場景慢慢的就能熟練運用了。其實這些函式極其類似,不同的函式可以完成同樣的功能,通過下面的例項也能看出。而在我以往的開發經驗中這些函式主要的使用場景有兩個,一是非空判斷,二是物件的初始化或者本身及方法的頻繁呼叫。

1. with

定義:fun <T, R> with(receiver: T, block: T.() -> R): R

功能:將物件作為函式的引數,在函式內可以通過 this指代該物件。返回值為函式的最後一行或return表示式。

例項: 1.在自定義view中當我們初始化畫筆時很多時候我們會寫下邊的程式碼

    var paint = Paint()
    paint.color = Color.BLACK
    paint.strokeWidth = 1.0f
    paint.textSize = 18.0f
    paint.isAntiAlias = true
複製程式碼

如果使用with,那麼就可以寫成這樣

var paint = Paint()
with(paint) {
        color = Color.BLACK
        strokeWidth = 1.0f
        textSize = 18.0f
        isAntiAlias = true
    }
複製程式碼

省去了paint.後書寫起來感覺會更加自然 2.在宣告一些集合的場景比如:

    var list= mutableListOf<String>()
    list.add("1")
    list.add("2")
    list.add("3")
複製程式碼

使用with可以寫成

var list = with(mutableListOf<String>()) {
        add("1")
        add("2")
        add("3")
        this
    }
複製程式碼

開發中還有很多場景可以使用with功能,理解了with的功能也就能夠靈活運用了。

2. takeIf和takeUnless

takeif

定義:fun T.takeIf(predicate: (T) -> Boolean): T?

功能:傳遞一個函式引數,如果函式結果為true,返回T物件,否則返回null。

例項:使用File檔案時通常會判斷file是否存在,比如

   var file = File("filePath")
    if (file.exists()) {
        //do something
    } else {
        return false
    }
複製程式碼

使用takeif後

var file = File("filePath").takeIf { it.exists() }?:return false
//do something
複製程式碼

takeUnless

定義:fun T.takeUnless(predicate: (T) -> Boolean): T?

功能:與takeIf相反,引數函式返回false時返回T物件,否則返回null,這裡不再舉例。

3. run

定義:

(1)fun run(block: () -> R): R (2)fun <T, R> T.run(block: T.() -> R): R

功能:呼叫run函式返回值為函式體最後一行,或return表示式。

例項: 返回最後一行

kotlin.run {
    println("11")
    println("22")
}
複製程式碼

結果:

I/System.out: 11

I/System.out: 22

返回return表示式,return後面的程式碼不再執行(注意寫法@run)

kotlin.run {
        return@run println("11")
        println("22")
    }
複製程式碼

結果: I/System.out: 11

4. repeat

定義:fun repeat(times: Int, action: (Int) -> Unit)

功能:重複執行action函式times次,times從0開始

例項:與for迴圈功能類似,例如

repeat(5){ println("count:$it") }
複製程式碼

等價於

for (i in 0..4) { println("count:$i") }
複製程式碼

或者

(0..4).forEach{println("count:$it")}
複製程式碼

5. let

定義:fun <T, R> T.let(block: (T) -> R): R

功能:呼叫物件(T)的let函式,則該物件為函式的引數。在函式內可以通過 it 指代該物件。返回值為函式的最後一行或指定return表示式。

例項:有點類似於run(),let在使用中可用於空安全驗證,變數?.let{} 例如

val data = ……
data?.let {
…… // 假如data不為null,程式碼會執行到此處
}
複製程式碼

6. apply

定義:fun T.apply(block: T.() -> Unit): T

功能:呼叫物件的apply函式,在函式範圍內,可以任意呼叫該物件的任意方法,並返回該物件。

例項:

var list = mutableListOf<Int>().apply {
    add(1)
    add(2)
    add(3)
}
複製程式碼

注意他和run函式的區別,run返回的是最後一行,apply返回的是物件本身,由apply函式的定義我們可以看出apply適用於那些物件初始化需要給其屬性賦值的情況。 還是用畫筆的例子

原始的

    var paint = Paint()
    paint.textSize = 14.0f
    paint.color = Color.WHITE
    paint.isAntiAlias = false
複製程式碼

使用apply後

    var paint = Paint().apply {
        textSize = 14.0f
        color = Color.WHITE
        isAntiAlias = false
    }
複製程式碼

此外由於apply函式返回的是其物件本身,那麼可以配合?.完成多級的非空判斷操作,或者用於建造者模式的Builder中

7. also

定義:fun T.also(block: (T) -> Unit): T

功能:呼叫物件的also函式,在函式塊內可以通過 it 指代該物件,返回值為該物件本身。(注意其和let函式的區別,let返回的是最後一行,also返回的是物件本身)

例項:需要返回物件本身(this)的情況下,例如建造者模式。

相關文章