ProgramaciónDesarrollador Kotlin Medio

¿Qué son las funciones de alcance en Kotlin (let, also, run, apply, with)? ¿Cuál es la diferencia entre estas funciones, cómo elegirlas para diferentes tareas, qué matices pueden surgir al utilizarlas? Proporcione ejemplos.

Supere entrevistas con el asistente de IA Hintsage

Respuesta.

Las funciones de alcance ("funciones de ámbito") en Kotlin son funciones estándar (let, also, run, apply, with) que permiten gestionar el contexto de ejecución de un bloque de código para un objeto. Se diferencian en:

  • tipo de valor devuelto,
  • cómo se accede al objeto dentro del bloque: a través de it o a través de this.

Comparación breve:

Funciónthis/itDevuelve¿Para qué?
letitresultadocadena de operaciones, trabajo con nullable, map
alsoitobjetoefectos secundarios, registro, depuración
runthisresultadocálculos, inicialización con retorno
applythisobjetoconfiguración de objeto, constructores
withthisresultadotrabajo con API externas, objeto "desde afuera"

Ejemplos:

  • let: conveniente si el objeto es nullable:
val str: String? = "Texto" str?.let { println(it.length) }
  • apply: configuración de objeto:
val paint = Paint().apply { color = Color.RED strokeWidth = 2f }
  • run: ejecución sobre el objeto, devuelve el resultado:
val length = "abcde".run { length }
  • with: para trabajar con un objeto externo:
val sb = StringBuilder() with(sb) { append("Hola, ") append("mundo!") toString() }
  • also: para efectos secundarios (por ejemplo, registros):
val list = mutableListOf(1, 2, 3) list.also { println("Antes: $it") }.add(4)

Aspectos a tener en cuenta:

  • let crea una copia del objeto en it, no es muy conveniente cambiar las propiedades del objeto.
  • apply y also siempre devuelven el mismo objeto (this / it), útil para constructores.
  • run/with a menudo se confunden: with es una función normal, no una extensión.

Pregunta tramposa.

¿Cuál es la diferencia entre let y also?

Respuesta:

  • Ambas utilizan it dentro del bloque,
  • let devuelve el resultado de la lambda, a menudo se usa para cadenas de transformación,
  • also devuelve el objeto original, se usa para efectos secundarios (registro, depuración), para no interferir en la cadena de transformación.

Ejemplo:

val result = listOf(1).also { println(it) }.map { it * 2 } // resultado — List<Int>

Ejemplos de errores reales debido a la falta de conocimiento de los matices del tema:


Historia

Un principiante utilizó let para configurar un objeto, pensando que podía cambiar su estado "en la cadena". Como resultado, al finalizar el bloque de configuración, obtenía no un objeto, sino el resultado de la lambda (por ejemplo, nada), lo que rompía la cadena de construcción de DSL.


Historia

Al escribir código para trabajar con objetos nullable, usaron run en lugar de let, sin notar la diferencia en el valor devuelto. Al final, el resultado de la expresión difería del esperado, apareciendo null donde no debería haber — la lógica de la aplicación se rompía.


Historia

En un gran constructor, usaron accidentalmente with para objetos internos, esperando el patrón de extensión. Dado que with no es una función de extensión, la cadena de varios bloques with no funcionaba correctamente, las llamadas internas se confundían y salían del objeto actual. Tuve que reescribir completamente la jerarquía de creación de objetos.