Hier sind einige Variationen, je nachdem, welchen Stil Sie verwenden möchten, ob Sie alle gleichen oder unterschiedlichen Typen haben und ob die Liste eine unbekannte Anzahl von Elementen enthält ...
Gemischte Typen, alle dürfen nicht null sein, um einen neuen Wert zu berechnen
Für gemischte Typen können Sie eine Reihe von Funktionen für jede Parameteranzahl erstellen, die zwar albern aussehen, für gemischte Typen jedoch gut funktionieren:
inline fun <T1: Any, T2: Any, R: Any> safeLet(p1: T1?, p2: T2?, block: (T1, T2)->R?): R? {
return if (p1 != null && p2 != null) block(p1, p2) else null
}
inline fun <T1: Any, T2: Any, T3: Any, R: Any> safeLet(p1: T1?, p2: T2?, p3: T3?, block: (T1, T2, T3)->R?): R? {
return if (p1 != null && p2 != null && p3 != null) block(p1, p2, p3) else null
}
inline fun <T1: Any, T2: Any, T3: Any, T4: Any, R: Any> safeLet(p1: T1?, p2: T2?, p3: T3?, p4: T4?, block: (T1, T2, T3, T4)->R?): R? {
return if (p1 != null && p2 != null && p3 != null && p4 != null) block(p1, p2, p3, p4) else null
}
inline fun <T1: Any, T2: Any, T3: Any, T4: Any, T5: Any, R: Any> safeLet(p1: T1?, p2: T2?, p3: T3?, p4: T4?, p5: T5?, block: (T1, T2, T3, T4, T5)->R?): R? {
return if (p1 != null && p2 != null && p3 != null && p4 != null && p5 != null) block(p1, p2, p3, p4, p5) else null
}
// ...keep going up to the parameter count you care about
Anwendungsbeispiel:
val risk = safeLet(person.name, person.age) { name, age ->
// do something
}
Führen Sie einen Codeblock aus, wenn die Liste keine Nullelemente enthält
Hier zwei Varianten: erstens das Ausführen eines Codeblocks, wenn eine Liste alle Nicht-Null-Elemente enthält, und zweitens, wenn eine Liste mindestens ein Nicht-Null-Element enthält. In beiden Fällen wird eine Liste von Nicht-Null-Elementen an den Codeblock übergeben:
Funktionen:
fun <T: Any, R: Any> Collection<T?>.whenAllNotNull(block: (List<T>)->R) {
if (this.all { it != null }) {
block(this.filterNotNull()) // or do unsafe cast to non null collectino
}
}
fun <T: Any, R: Any> Collection<T?>.whenAnyNotNull(block: (List<T>)->R) {
if (this.any { it != null }) {
block(this.filterNotNull())
}
}
Anwendungsbeispiel:
listOf("something", "else", "matters").whenAllNotNull {
println(it.joinToString(" "))
} // output "something else matters"
listOf("something", null, "matters").whenAllNotNull {
println(it.joinToString(" "))
} // no output
listOf("something", null, "matters").whenAnyNotNull {
println(it.joinToString(" "))
} // output "something matters"
Eine geringfügige Änderung, damit die Funktion die Liste der Elemente empfängt und dieselben Vorgänge ausführt:
fun <T: Any, R: Any> whenAllNotNull(vararg options: T?, block: (List<T>)->R) {
if (options.all { it != null }) {
block(options.filterNotNull()) // or do unsafe cast to non null collection
}
}
fun <T: Any, R: Any> whenAnyNotNull(vararg options: T?, block: (List<T>)->R) {
if (options.any { it != null }) {
block(options.filterNotNull())
}
}
Anwendungsbeispiel:
whenAllNotNull("something", "else", "matters") {
println(it.joinToString(" "))
} // output "something else matters"
Diese Variationen könnten geändert werden, um Rückgabewerte wie zu haben let()
.
Verwenden Sie das erste Nicht-Null-Element (Coalesce).
Geben Sie ähnlich wie bei einer SQL Coalesce-Funktion das erste Nicht-Null-Element zurück. Zwei Varianten der Funktion:
fun <T: Any> coalesce(vararg options: T?): T? = options.firstOrNull { it != null }
fun <T: Any> Collection<T?>.coalesce(): T? = this.firstOrNull { it != null }
Anwendungsbeispiel:
coalesce(null, "something", null, "matters")?.let {
it.length
} // result is 9, length of "something"
listOf(null, "something", null, "matters").coalesce()?.let {
it.length
} // result is 9, length of "something"
Andere Variationen
... Es gibt andere Variationen, aber mit einer genaueren Spezifikation könnte dies eingegrenzt werden.