Lo que quiero decir es seguir.
Considere este código:
// Can be a Long or null val data1= param1.toLongOrNull() val data2= param2.toLongOrNull() val dataN= paramN.toLongOrNull() // Proceed with the action if ALL of the data are not nulls if(notNull(data1, data2, dataN)){ // do something with data1,2,N } notNull() es una función de utilidad que acepta una lista de argumentos variables. Devuelve verdadero si todos los argumentos no son nulos.
fun <T> notNull(vararg elements: T): Boolean { elements.forEach { if (it == null) { return false } } return true } El problema que tengo es que Kotlin no sabe que dentro del bloque if , data1,2,N no puede ser nulo. Como resultado, esto no se puede compilar:
if(notNull(data1, data2, dataN)){ data1 + data2 + dataN // Fail: Required Long, Found Long? // Operator + not allowed on nullable receiver. }Por otro lado, si las variables se verifican explícitamente contra nulo, entonces Kotlin sabe que está bien y no se queja.
if(data1!=null && data2!=null && dataN!=null){ data1 + data2 + dataN } Sería bueno "configurar" el método notNull de tal manera, para que Kotlin sepa que una vez que devuelve verdadero, cualquiera de los parámetros pasados no puede ser nulo dentro del bloque.
es posible?
Obviamente hay múltiples formas de despellejar a un gato, pero podrías hacer algo como esto:
inline fun <T> doIfNotNull(elements: Array<T?>, block : (Array<T>) -> Unit) { val validElements = arrayListOf<T>() for (i in elements) { if (i == null) return validElements.add(i) } block.invoke(validElements.toArray(elements)) }Usar con varargs (tiene que ser el último parámetro, haciendo que el receptor funcione como primer argumento, lo que no se siente tan bien);
inline fun <T> doIfNotNull(block : (Array<T>) -> Unit, vararg elements : T?) { val validElements = arrayListOf<T>() for (i in elements) { if (i == null) return validElements.add(i) } block.invoke(validElements.toArray(elements)) }Ejemplo :
fun test() { val elements = arrayOf(1L, 2L, null) doIfNotNull(elements, { it.sum() }) }