ProgramaciónDesarrollador de Kotlin

¿Cómo se implementan funciones de orden superior y expresiones lambda en Kotlin? Describe los matices de la transmisión y el retorno de funciones, las características de la sintaxis, las principales limitaciones y proporciona ejemplos de código.

Supere entrevistas con el asistente de IA Hintsage

Respuesta.

Funciones de orden superior — son funciones que aceptan otras funciones como parámetros o las devuelven. Kotlin utiliza expresiones lambda para pasar comportamientos como valores de manera conveniente.

Ejemplo de declaración:

fun operateOnNumbers(a: Int, b: Int, operation: (Int, Int) -> Int): Int { return operation(a, b) } val sum = operateOnNumbers(3, 2) { x, y -> x + y } // sum = 5

Transmisión de funciones:

  • Las funciones se pueden pasar no solo como expresiones lambda, sino también como referencias: :
fun multiply(x: Int, y: Int) = x * y operateOnNumbers(2, 3, ::multiply)

Retorno de la función:

fun makeMultiplier(factor: Int): (Int) -> Int = { x -> x * factor } val triple = makeMultiplier(3) val result = triple(10) // 30

Características:

  • La lambda puede tener no más de un parámetro no nombrado (it).
  • Se pueden pasar parámetros nombrados a la función, pero los tipos deben ser explícitamente indicados si no se puede deducir el tipo.
  • Las expresiones lambda son objetos (clases anónimas), lo que afecta el rendimiento en un gran número de llamadas en bucles calientes (se resuelve con funciones inline).
  • Para las lambdas que capturan variables se utiliza el closure (cierre).

Pregunta capciosa.

¿Cuál es la diferencia entre declarar el tipo de función (Int, Int) -> Int y usar el tipo Function2<Int, Int, Int>?

Respuesta: La sintaxis (Int, Int) -> Int es simplemente una declaración "más bonita" (azúcar sintáctico) para la interfaz Function2<Int, Int, Int>. En la práctica, ambas variantes son completamente intercambiables.

val f1: (Int, Int) -> Int = { x, y -> x + y } val f2: Function2<Int, Int, Int> = { x, y -> x + y }

Pero la primera opción es generalmente preferida por su legibilidad.

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


Historia

En un sistema grande de procesamiento de eventos se crearon decenas de expresiones lambda dentro de un bucle sin usar funciones inline. Esto causó una alta carga en el GC y degradación del rendimiento, ya que para cada llamada se creaba un objeto anónimo de función separado.


Historia

Al intentar devolver una función de otra función, no se especificó correctamente la firma de la función devuelta, lo que llevó a un error de compilación y una larga búsqueda de la causa. El error estaba en la falta de paréntesis en el tipo: fun foo(): Int -> Int en lugar de fun foo(): (Int) -> Int correcto.


Historia

Un desarrollador intentó usar una lambda sin señalar explícitamente el tipo como parámetro de otra función con un tipo no deducido explícitamente, lo que resultó en el error "cannot infer a type for this parameter". El problema se resolvió al indicar explícitamente el tipo de la lambda o el parámetro de la función.