Kotlin: ¿cómo pasar una función como parámetro? Lo analizamos con ejemplos
\n\n¡Hola, amigo! Si alguna vez has escrito en Kotlin y te has preguntado: "¿Cómo pasar una función como parámetro a otra función?" — entonces has llegado al lugar indicado. Esta pregunta en Stack Overflow ha acumulado miles de visitas, y no es de extrañar. La programación funcional en Kotlin no es solo una característica de moda, sino una herramienta poderosa que hace que el código sea más limpio, más corto y más expresivo.
\n\nEn este artículo no solo daremos una respuesta seca. Analizaremos todo, desde expresiones lambda simples hasta técnicas avanzadas. Aprenderás a usar los tipos Function, el operador de referencia a función ::, e incluso cómo evitar errores típicos de principiantes. ¡Allá vamos!
¿Por qué es importante? Tres razones para usar funciones como parámetros
\n\n- \n
- Flexibilidad: Puedes escribir una función que haga cosas diferentes dependiendo de qué función le pases. \n
- Legibilidad: El código se vuelve declarativo: describes qué hacer, no cómo hacerlo. \n
- Reutilización: Eliminas la duplicación de código extrayendo patrones comunes en funciones de orden superior. \n
Fundamentos: tipos de funciones (Function Types)
\n\nEn Kotlin, las funciones son objetos de primera clase. Esto significa que tienen su propio tipo. El tipo de una función se describe así: (Parámetros) -> TipoDeRetorno. Por ejemplo:
// Función que toma un Int y devuelve un String\nval intToString: (Int) -> String = { number -> "Número: $number" }\n\n// Función que no toma nada y no devuelve nada\nval doNothing: () -> Unit = { println("¡Hola!") }\n\n// Función con dos parámetros\nval sum: (Int, Int) -> Int = { a, b -> a + b }\n\n\nObserva el Unit — es el análogo de void en Java/JavaScript. Si una función no devuelve nada, su tipo es () -> Unit.
Cómo pasar una función como parámetro: primer ejemplo
\n\nSupongamos que escribimos una función que realiza alguna operación sobre un número dos veces. En lugar de codificar la operación de forma fija, la pasaremos como parámetro:
\n\nfun applyTwice(x: Int, operation: (Int) -> Int): Int {\n val firstResult = operation(x)\n return operation(firstResult)\n}\n\n// Uso:\nval result = applyTwice(5) { it * 2 } // Lambda\nprintln(result) // Imprime: 20 (5*2 = 10, 10*2 = 20)\n\n// O con una función nombrada:\nfun double(x: Int) = x * 2\nval result2 = applyTwice(5, ::double)\nprintln(result2) // También 20\n\n\n¿Ves qué elegante? En el primer caso usamos una expresión lambda (función anónima), y en el segundo, una referencia a una función existente mediante el operador ::. Ambas formas son válidas, y las analizaremos en detalle.
Formas de pasar una función (análisis detallado)
\n\n1. Expresiones lambda (la forma más popular)
\n\nUna lambda es una función anónima que se puede pasar directamente. En Kotlin, las lambdas tienen una sintaxis concisa:
\n\nval list = listOf(1, 2, 3, 4, 5)\n\n// Pasamos una lambda a la función filter\nval evenNumbers = list.filter { it % 2 == 0 }\nprintln(evenNumbers) // [2, 4]\n\n// Si hay varios parámetros:\nval numbersWithIndex = list.mapIndexed { index, value -> "$index: $value" }\nprintln(numbersWithIndex) // ["0: 1", "1: 2", ...]\n\n\nImportante: Si la lambda es el último parámetro de una función, se puede sacar fuera de los paréntesis. Esto hace que el código se parezca a construcciones integradas del lenguaje. Así es como funcionan filter, map, forEach y otras.
Ejemplo con especificación explícita del parámetro (cuando hay más de un parámetro):
\n\nfun performAction(a: Int, b: Int, action: (Int, Int) -> String) {\n println(action(a, b))\n}\n\n// Llamada con lambda\nperformAction(3, 4) { x, y -> "Suma: ${x + y}" }\n