在Kotlin的標準函式,有兩大函式,即takeIf
和takeUnless
,乍一看,有什麼特別之處呢?這幾乎就是if
?
或者極端點,把每一個if
語句改成類似下面(不推薦)。
//原始程式碼
if(status){doThis()}
//修改後的程式碼
takeIf {status}?apply {doThis()}
複製程式碼
深入探討
像其他任何東西一樣,takeIf
(或takeUnless
)確實有它的使用場景。我通過不同情況分享我對他們的理解。在此之前,讓我們看看它的實現。
函式簽名
public inline fun <T> T.takeIf(predicate: (T) -> Boolean): T?
= if (predicate(this)) this else null
複製程式碼
從函式簽名,我們注意到
- 它是從T物件本身呼叫的。即
T.takeIf
, predicate
函式以T物件為引數- 等待
predicate
評估後它返回this
或null
。
合理的使用情況
基於以上特點,我可以推匯出它相對於if
的使用情況,如下:
1.它是從T物件本身呼叫的。即T.takeIf
,
它可以很好處理可空性檢查。一個例子如下
//原始程式碼
if(someObject!= null && status){
doThis()
}
//改進的程式碼
someObject?.takeIf {status}?apply {doThis()}
複製程式碼
2.predicate
函式以T物件為引數
由於將T作為predicate
的引數,所以可以進一步簡化takeIf
程式碼
//原始程式碼
if(someObject!= null && someObject.status){
doThis()
}
//更好的程式碼
if(someObject?.status == true){
doThis()
}
//改進的程式碼
someObject?.takeIf {it.status} ?. apply {doThis()}
複製程式碼
更好的程式碼
的確還可以,但需要顯式的true
關鍵詞,所以並不理想。
3.等待predicate
評估後它返回this
或null
既然它返回this
,那就可以用來進行鏈式呼叫。因此,下面程式碼可以優化
//原始程式碼
if(someObject!= null && someObject.status){
someObject.doThis()
}
//改進的程式碼
someObject?.takeIf {status}?doThis()
複製程式碼
或者實現獲取資料或退出的更好方式(例子從Kotlin Doc中摘取)
val index
= input.indexOf(keyword).takeIf {it> = 0}?:error(“Error”)
val outFile
= File(outputDir.path).takeIf {it.exists()}?:return false
複製程式碼
注意
看看下面的程式碼。
//語法上仍然正確。但邏輯錯誤!
someObject?.takeIf {status} .apply {doThis()}
//正確的(注意可空性檢查?)
someObject?.takeIf {status} ?.apply {doThis()}
複製程式碼
doThis()
在第一行中不管status
true 還是 false 都會執行。因為 即使takeIf
返回null
,它仍然會被呼叫。(這裡假設doThis()
不是someObject
的函式)
所以在這裡,第二行的?
是非常微妙且重要的。