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)的情況下,例如建造者模式。