Aquí hay algunas variaciones, según el estilo que desee usar, si tiene todo de tipos iguales o diferentes, y si la lista tiene un número desconocido de elementos ...
Tipos mixtos, todos no deben ser nulos para calcular un nuevo valor
Para los tipos mixtos, puede crear una serie de funciones para cada recuento de parámetros que pueden parecer tontas, pero funcionan bien para los tipos mixtos:
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
Ejemplo de uso:
val risk = safeLet(person.name, person.age) { name, age ->
// do something
}
Ejecute bloque de código cuando la lista no tenga elementos nulos
Aquí hay dos opciones, la primera para ejecutar un bloque de código cuando una lista tiene todos los elementos no nulos, y la segunda para hacer lo mismo cuando una lista tiene al menos un elemento no nulo. Ambos casos pasan una lista de elementos no nulos al bloque de código:
Funciones:
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())
}
}
Ejemplo de uso:
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"
Un ligero cambio para que la función reciba la lista de elementos y realice las mismas operaciones:
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())
}
}
Ejemplo de uso:
whenAllNotNull("something", "else", "matters") {
println(it.joinToString(" "))
} // output "something else matters"
Estas variaciones podrían ser cambiado a tener valores de retorno como let()
.
Utilice el primer elemento no nulo (fusión)
Similar a una función de fusión SQL, devuelve el primer elemento no nulo. Dos sabores de la función:
fun <T: Any> coalesce(vararg options: T?): T? = options.firstOrNull { it != null }
fun <T: Any> Collection<T?>.coalesce(): T? = this.firstOrNull { it != null }
Ejemplo de uso:
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"
Otras variaciones
... Hay otras variaciones, pero con una mayor especificación, esto podría reducirse.