次のコードがあるとします:
class QuickExample {
fun function(argument: SomeOtherClass) {
if (argument.mutableProperty != null ) {
doSomething(argument.mutableProperty)
} else {
doOtherThing()
}
}
fun doSomething(argument: Object) {}
fun doOtherThing() {}
}
class SomeOtherClass {
var mutableProperty: Object? = null
}
Javaの場合とは異なり、実行時にnullの逆参照を心配するために放置される可能性がありますが、これはコンパイルされません。もちろん、mutableProperty
は 'if'内で一度nullになることはありません。
私の質問は、これを処理する最良の方法は何ですか?
いくつかのオプションが明らかです。新しい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スタイルの方法よりも扱いにくく冗長です。
私は何かが欠けていますか?これを達成するための好ましいイディオムはありますか?
私はそれを達成するための本当に「短い」方法があるとは思わないが、あなたは単にwith
またはlet
内で条件を使うことができる:
with(mutableVar) { if (this != null) doSomething(this) else doOtherThing() }
mutableVar.let { if (it != null) doSomething(it) else doOtherThing() }
実際、可変値の「キャプチャ」は、let
の主な使用例の1つです。
これはwhen
ステートメントと同等です。
説明したオプションが常にあり、それを変数に割り当てます。
val immutable = mutableVar
if (immutable != null) {
doSomething(immutable)
} else {
doOtherThing()
}
これは、たとえば、物事は冗長になりすぎます。
Niceこれを達成する方法は、おそらくlastラムダ引数は()
の外側に置くことができます。そのため、2を指定しても、他のすべての標準関数の構文には実際には適合しません。
気にしない場合(またはメソッド参照を渡す場合)は、couldで記述できます。
inline fun <T : Any, R> T?.ifNotNullOrElse(ifNotNullPath: (T) -> R, elsePath: () -> R)
= let { if(it == null) elsePath() else ifNotNullPath(it) }
...
val a: Int? = null
a.ifNotNullOrElse({ println("not null") }, { println("null") })
更新:
コメントでフランタが述べたように、メソッドdoSomething()
がnullを返す場合、elvis演算子の右側のコードが実行されますが、ほとんどの場合、これは望ましいケースではありません。しかし同時に、この場合、doSomething()
メソッドは何かを行うだけで、何も返さない可能性が非常に高いです。
代替案:プロトタイプがコメントで言及したように、also
は関数ブロックの結果ではなくlet
オブジェクトを返すため、also
ではなくthis
を使用できます。
mutableProperty?.also { doSomething(it) } ?: doOtherThing()
元の答え:
let
を エルビス演算子 とともに使用します。
mutableProperty?.let { doSomething(it) } ?: doOtherThing()
ドキュメントから:
?:の左側の式がnullでない場合、elvis演算子はそれを返し、そうでない場合は右側の式を返します。右側の式は、左側がヌルの場合にのみ評価されることに注意してください。
右側の式の後のコードブロックの場合:
mutableProperty?.let {
doSomething(it)
} ?: run {
doOtherThing()
doOtherThing()
}
以下のようにカスタムインライン関数を追加します。
inline fun <T> T?.whenNull(block: T?.() -> Unit): T? {
if (this == null) block()
return this@whenNull
}
inline fun <T> T?.whenNonNull(block: T.() -> Unit): T? {
this?.block()
return this@whenNonNull
}
次のようなコードを書くことができます:
var nullableVariable :Any? = null
nullableVariable.whenNonNull {
doSomething(nullableVariable)
}.whenNull {
doOtherThing()
}
次のようなこともできます。
class If<T>(val any: T?, private val i: (T) -> Unit) {
infix fun Else(e: () -> Unit) {
if (any == null) e()
else i(any)
}
}
その後、次のように使用できます。
If(nullableString) {
//Use string
} Else {
}
私は通常このように書きます:
takeIf{somecondition}?.also{put somecondition is met code}?:run{put your else code here}
takeIfが必須である後の疑問符に注意してください。キーワードを使用することも、キーワードを適用することもできます。