El operador let en Kotlin

video[Tutorial El operador let en Kotlin

Durante la programación de aplicaciones nos encontraremos con la siguiente situación en varias ocasiones:

var propiedad: Int? = 42
fun unMetodo() {
    if (propiedad != null) {
        print(propiedad) // Error: aunque la acabamos de comprobar es null 
    }
} 
Y es que, dado que estamos utilizando una variable mutable (propiedad), el valor de la misma podrá ser cambiado por otro hilo, justo después de haber hecho la comprobación. Una alternativa rápida, que es utilizada por el sistema al importar código Java, es utilizar el operador !! pero, como hemos comentado, es un operador que debemos evitar en la medida de lo posible.
Otra posible solución sería crear una copia de solo lectura de dicha varia-ble:
var propiedad: Int? = 42
fun unMetodo() {
    val copia = propiedad
    if (copia != null) {
        print(copia)
    }
} 
El código anterior compila, pero una de las ventajas de Kotlin es la reduc-ción de código innecesario (boilerplate code) y dicho código no encaja con esta filosofía, ya que lo único que hacemos es añadir más líneas de código.
Una alternativa más adecuada será utilizar el operador let, el cual, internamente, crea una copia de la variable a comprobar en una variable inmutable local que será utilizada en el bloque definido a continuación. De este modo, podríamos pensar en una posible solución como la siguiente:
var propiedad: Int? = 42
fun unMetodo() {
    propiedad.let {
        print(it) 
    }
}  
En este ejemplo, la función let verifica si propiedad es null. En caso de no serlo, realiza una copia de propiedad en it y ejecuta el Lambda.
Esta solución es válida, pero si dentro del bloque let necesitamos llamar a una función con su valor, puede que nos encontremos con un error.
var propiedad: Int? = 42
fun unMetodo() {
    propiedad.let {
        imprimir(it) // error
    }
}
fun imprimir(int: Int) {
    print(int)
}  
En este caso, nuestra función imprimir necesita un valor de tipo Int y recibe un valor de tipo Int?. Por suerte, este tipo de error es muy sencillo de solventar con el operador ?., el cual nos va permitir llamar de un modo seguro a nuestro operador let.
var propiedad: Int? = 42
fun unMetodo() {
    propiedad?.let {
        imprimir(it)
    }
}
fun imprimir(int: Int) {
    print(int)
}  
La función let es más compleja. Si nos fijamos en su implementación, ve-remos que, además de la variable con la que llamamos a la función T, tenemos un valor de retorno R.
inline fun <T, R> T.let(block: (T) -> R): R 
Veamos un código más completo donde mostrar la interacción de nuestra clase con el resto del código:
class MiClase {
    var propiedad: Int? = 42

    fun unMetodo() {
        val valor = propiedad?.let {
            imprimir(it)
            "correcto"
        }
    }
    fun imprimir(i: Int) {
        print(i)
    }
} 
En este ejemplo, aparte de imprimir el valor de la variable, devolvemos una cadena de texto indicando que se ha ejecutado el bloque del let. Pero ¿qué pasa en caso de que propiedad sea null?
Es una buena práctica de programación cubrir esta vía, para lo que podemos recurrir al operador Elvis. De este modo, si la variable existe la capturaremos y la usaremos, y si es null mostraremos un mensaje de error:
fun unMetodo() {
    propiedad?.let {
        imprimir(it)
    } ?: run {
        mostrarError()
    }
} 
De este modo, podremos utilizar el valor devuelto por bloque let para in-formar al usuario, algo que sin el bloque de Elvis no era posible.
class MiClase {
    var propiedad: Int? = 42
    fun unMetodo() {
        val valor = propiedad?.let {
            imprimir(it)
            "correcto"
        } ?: run {
            imprimir("ERROR")
            "sin Valor"  
        }
    }
    fun imprimir(i: Int) {
        print(i)
    }
    fun imprimir(string: String) {
        print(string)
    }
} 
Preguntas de repaso: Tratamiento de null