使用Kotlin takeIf(或takeUnless)

adison發表於2018-01-24

原文連結

在Kotlin的標準函式,有兩大函式,即takeIftakeUnless,乍一看,有什麼特別之處呢?這幾乎就是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
複製程式碼

從函式簽名,我們注意到

  1. 它是從T物件本身呼叫的。即T.takeIf
  2. predicate函式以T物件為引數
  3. 等待predicate評估後它返回thisnull

合理的使用情況

基於以上特點,我可以推匯出它相對於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評估後它返回thisnull

既然它返回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()在第一行中不管statustrue 還是 false 都會執行。因為 即使takeIf返回null,它仍然會被呼叫。(這裡假設doThis()不是someObject的函式)

所以在這裡,第二行的? 是非常微妙且重要的。

相關文章