假設我有三個函式foo, bar, baz,它們都回傳可為空的型別。
fun foo(): Int? = 1
fun bar(): Int? = 2
fun baz(): Int? = 3
我想呼叫它們,如果它們都回傳非空值,我想從它們的回傳值中計算一個值。
我可以用statements做到這一點,如下所示:
val x = foo()
val y = bar()
val z = baz()
val result = if (x != null && y != null && z != null) x y z else null
但是,我不喜歡我必須宣告 3 個額外的變數,之后我仍然可以訪問這些變數。通過有 3 個這樣的額外陳述句,這也意味著我不能使用運算式主體函式,如果我正在撰寫一個回傳的函式result。
如果我使用lets 代替:
val result = foo()?.let { x ->
bar()?.let { y ->
baz()?.let { z ->
x y z
}
}
}
這會創建一個深層嵌套。如果只有一個函式,這樣就好了,但是如果有3個或更多函式,這讓我的意圖“呼叫這三個函式,如果它們都是非空的,將它們加在一起”就不太清楚了。
我怎樣才能以一種清楚地表達我的意圖的方式來寫這個,同時又使它成為一個單一的表達方式?
uj5u.com熱心網友回復:
如果它們屬于不同的型別,我認為您需要撰寫自己的輔助函式,例如(不同數量的引數需要不同的多載,因為編譯器沒有其他方法可以知道引數的型別):
inline fun <T : Any, U : Any, R> ifAllNotNull(t: T?, u: U?, block: (t: T, u: U) -> R): R? {
return when {
t != null && u != null -> block(t, u)
else -> null
}
}
inline fun <T : Any, U : Any, V : Any, R> ifAllNotNull(t: T?, u: U?, v: V?, block: (t: T, u: U, v: V) -> R): R? {
return when {
t != null && u != null && v != null -> block(t, u, v)
else -> null
}
}
val result = ifAllNotNull(foo(), bar(), baz()) { x, y, z -> x y z }
請注意,在檢查任何三個引數是否為空之前,將評估所有三個引數。
或者,如果您只想使用標準庫函式執行您描述的操作(在結果計算后隱藏三個變數),您可以使用run來限制臨時變數的范圍:
val result = run {
val x = foo()
val y = bar()
val z = baz()
if (x != null && y != null && z != null) x y z else null
}
如果您愿意,這也將使您有機會短路:
val result = run {
val x = foo() ?: return@run null
val y = bar() ?: return@run null
val z = baz() ?: return@run null
x y z
}
uj5u.com熱心網友回復:
您可以過濾掉所有null-values 并僅在串列上應用一個操作,如果它沒有縮小大小,例如:
fun sumIfNoneNull(values: List<Int?>): Int? = values
.filterNotNull()
.takeIf { it.size == values.size }
?.sum()
人們可以進一步概括這一點,例如:
fun <T, R> List<T>.foldIfNoneNull(
initial: R,
operation: (acc: R, T) -> R
): R? = this
.filterNotNull()
.takeIf { nonNullList -> nonNullList.size == this.size }
?.fold(initial, operation)
您可以像使用其他任何東西一樣使用它fold,例如:
listOf(foo(), bar(), baz()).foldIfNoneNull(0) { acc, cur -> acc cur }
uj5u.com熱心網友回復:
val result = listOf(foo(), bar(), baz())
.reduce { acc, i ->
when {
acc == null || i == null -> null
else -> acc i
}
}
或作為函式:
fun <T> apply(operation: (T, T) -> T, vararg values: T?): T? {
return values
.reduce { acc, i ->
when {
acc == null || i == null -> null
else -> operation(acc, i)
}
}
}
val result = apply({ x, y -> x y }, foo(), bar(), baz())
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/430321.html
