2017-08-25 59 views
4

假設我們有這樣的代碼來寫,「如果不爲空,否則......」在運行時空解除引用,這不會編譯 - 非常正確。當然,mutableProperty在'if'中可能不再爲空。科特林和習慣的方法根據各地可變值

我的問題是處理這個問題的最好方法是什麼?

有幾個選項是顯而易見的。在不使用任何新的Kotlin語言功能的情況下,最簡單的方法顯然是將該值複製到方法範圍內,而後者不會隨之改變。

有這樣的:

fun function(argument: SomeOtherClass) { 
    argument.mutableProperty?.let { 
     doSomething(it) 
     return 
    } 
    doOtherThing() 
} 

這具有明顯的缺點,你需要提前歸還或以其他方式避免執行後續的代碼 - 確定在特定的小環境中,但有一個氣味它。

然後有這種可能性:

fun function(argument: SomeOtherClass) { 
    argument.mutableProperty.let { 
     when { 
      it != null -> { 
       doSomething(it) 
      } 
      else -> { 
       doOtherThing() 
      } 
     } 
    } 
} 

,但同時它的目的更加清晰,可以說這是不是處理這個問題的Java風格的方式更笨拙和冗長。

我錯過了什麼,有沒有一個首選的習慣用法來達到這個目的?

+1

國際海事組織我真的會認爲,簡單地'with(argument.mutableProperty){i f(this!= null)a(this)else b()}'足夠簡潔(或者與'let'等價)。通常這不應該成爲一個大問題,並且這個問題仍然很短。 – Moira

+0

看起來不錯,謝謝!我建議你把它作爲答案加入 - 至少,這是實現它的另一種方式。 –

回答

3

我不相信有真正的「短」的方式來實現它,但是你可以簡單地使用條件中withlet

with(mutableVar) { if (this != null) doSomething(this) else doOtherThing() } 
mutableVar.let { if (it != null) doSomething(it) else doOtherThing() } 

這相當於你when聲明。

總有你所描述的選項,將其分配給一個變量:

val immutable = mutableVar 

if (immutable != null) { 
    doSomething(immutable) 
} else { 
    doOtherThing() 
} 

這始終是一個很好的回退的情況下,例如事情變得太冗長。因爲只有最後拉姆達參數允許()以外的地方放,所以指定兩個不會真的適合所有的語法

有可能是沒有真正實現這是一個非常不錯方式其他標準功能。

可以寫一個,如果你不介意(或者,如果你會被傳遞方法的引用來):

inline fun <T : Any, R> T?.ifNotNullOrElse(ifNotNullPath: (T) -> R, elsePath:() -> R) 
     = let { if(it == null) elsePath() else ifNotNullPath(it) } 
4

我會用letElvis operator

mutableProperty?.let { doSomething(it) } ?: doOtherThing() 

從DOC:

如果表達式的左側:不爲空,Elvis操作符 返回它,否則返回表達的權利。注意 只有當左側 側爲空時才評估右側表達式。

對於代碼的右側表達之後的塊:

mutableProperty?.let { 
      doSomething(it) 
     } ?: run { 
      doOtherThing() 
      doOtherThing() 
     } 
+1

這樣做的缺點似乎是限制了RHS上的單個方法調用,而不是一段代碼。我是否錯過了這個數字的任何詭計? –

+1

@RobPridham我想你可以在技術上使用['run'](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/run.html)並在其中使用lambda表達式,但這是一個延伸 – Moira

+1

是。正如@ 1blustone所提到的,可以使用'run'或'let'。或者你可以寫一個功能塊並通過調用'.invoke()'或者在關閉lambda後面加上'()'來調用它,但是這個函數不會被內聯。 – Bob

0

添加自定義內聯函數如下:

inline fun <T> T?.whenNull(block: T?.() -> Unit): T? { 
    if (this == null) block() 
    return [email protected] 
} 

inline fun <T> T?.whenNonNull(block: T.() -> Unit): T? { 
    this?.block() 
    return [email protected] 
} 

則可以像這樣編寫代碼:

var nullableVariable :Any? = null 
nullableVariable.whenNonNull { 
    doSomething(nullableVariable) 
}.whenNull { 
    doOtherThing() 
}