Declaración de funciones
Las funciones son una herramienta fundamental para construir software reutilizable, legible y organizado. Kotlin facilita su declaración con una sintaxis concisa y expresiva, que incluye características como parámetros con valores por defecto, funciones de una sola expresión e inferencia de tipos.
En esta lección aprenderás a declarar funciones en Kotlin, entender cómo funciona vararg
para aceptar múltiples argumentos y cuándo conviene especificar tipos de retorno. También explorarás funciones estándar como map
y fold
, y conocerás las diferencias entre colecciones como Array
y List
.
No es necesario dominar todos los detalles de inmediato: a medida que avancemos en el curso, retomaremos y profundizaremos en los elementos más relevantes.
🧩 Funciones en Kotlin
Una función en Kotlin es un bloque de código reutilizable que realiza una tarea específica. La sintaxis básica para declarar una función es la siguiente:
fun functionName(param1: Type1, param2: Type2 = defaultValue, ...): ReturnType {
// Cuerpo de la función
return result
}
Explicación de la sintaxis
fun
: Palabra clave para declarar una función.functionName
: Nombre descriptivo que identifica la función.- Parámetros (
param1
,param2
): Lista de argumentos con sus tipos.- Una función puede no tener parámetros.
- Es posible definir valores por defecto, haciendo que el parámetro sea opcional.
ReturnType
: Tipo del valor que retorna la función.- Si la función no devuelve un valor significativo, se usa
Unit
, que puede omitirse por ser implícito.
- Si la función no devuelve un valor significativo, se usa
- Cuerpo de la función: Conjunto de instrucciones que se ejecutan al llamarla.
➕ Ejemplo: Sumar dos números
Supongamos que queremos crear una función que sume dos números enteros. La declaración sería:
fun add(a: Int, b: Int): Int {
return a + b
}
Si la función contiene solo una expresión, puedes escribirla de forma más concisa mediante asignación directa:
fun add(a: Int, b: Int): Int = a + b
Kotlin incluso permite inferir el tipo de retorno automáticamente:
fun add(a: Int, b: Int) = a + b
Este estilo hace que el código sea más breve, pero úsalo con moderación: puede dificultar la lectura si el tipo de retorno no es evidente y volver el código más frágil frente a cambios accidentales en el tipo devuelto.
Inferencia de tipos
Kotlin es un lenguaje con inferencia de tipos, lo que significa que el compilador puede deducir el tipo de una variable o expresión a partir del contexto.
En el ejemplo anterior, como la función consiste en una sola expresión, el tipo de retorno se infiere automáticamente.
No abuses de la inferencia
Aunque la inferencia puede hacer el código más limpio y conciso, no siempre conviene omitir los tipos.
En funciones públicas, con lógica más compleja o expuestas como parte de una API, declarar el tipo explícitamente mejora la claridad, actúa como documentación implícita y facilita la evolución del código.
Estilo de nombres
En Kotlin, las funciones y variables deben nombrarse usando la convención camelCase
. Esto significa:
- El nombre comienza con minúscula.
- Cada palabra siguiente se escribe sin espacios, comenzando con mayúscula.
✅ Ejemplos correctos:
calculateTotal
printMessage
main
Usar un estilo de nombres consistente mejora la legibilidad y asegura que tu código se mantenga alineado con las prácticas idiomáticas de Kotlin.
Estilos incorrectos
Evita estilos heredados de otros lenguajes o no válidos en Kotlin:
CalculateTotal
→ ❌ PascalCase, reservado para clases y tipos.calculate_total
→ ❌ snake_case, típico en Python, no se utiliza en Kotlin.calculate-total
→ ❌ kebab-case, inválido como identificador.CALCULATE_TOTAL
→ ❌ Reservado para constantes y valores inmutables en tiempo de compilación.
🔢 Funciones variádicas (vararg
)
En Kotlin puedes definir funciones que aceptan una cantidad variable de argumentos usando la palabra clave vararg
.
Esto permite invocar la función con cero, uno o más valores del mismo tipo, de manera similar a *args
en Python o ...args
en JavaScript.
fun sumAll(vararg nums: Int): Int =
nums.sum()
sumAll(1, 2, 3, 4) // devuelve 10
sumAll() // devuelve 0
Si tienes un arreglo existente, puedes desempaquetarlo usando el prefijo *
:
val extras = intArrayOf(5, 6)
sumAll(1, 2, *extras) // devuelve 14
Hack: Uno o más argumentos
Si necesitas que una función reciba al menos un argumento obligatorio, puedes declararlo como un parámetro normal seguido de un vararg
.
Una forma útil de entender esto es compararlo con expresiones regulares:
*
representa “cero o más repeticiones”+
representa “una o más repeticiones”
En este contexto:
- El parámetro obligatorio representa el
+
- El
vararg
representa el*
Juntos, expresan la idea de “uno o más argumentos”.
fun sumTo(first: Int, vararg rest: Int): Int =
rest.fold(first) { acc, i -> acc + i }
sumTo(1) // devuelve 1
sumTo(1, 2, 3, 4) // devuelve 10
sumTo(first = 1, rest = intArrayOf(2, 3, 4)) // devuelve 10
Este patrón también sirve para funciones con dos o más parámetros obligatorios, seguidos por una cantidad variable de argumentos opcionales.
vararg
vs. Array
En Kotlin, vararg
es una forma conveniente de permitir que una función reciba una cantidad variable de argumentos.
Internamente, el compilador convierte esos argumentos en un arreglo (Array<T>
, IntArray
, etc.).
Esto significa que:
- Usar
vararg
es azúcar sintáctico2 sobre una función que acepta un arreglo. - Puedes seguir llamando a la función con un arreglo existente usando el operador
*
para desempaquetarlo.
fun sumAll(vararg nums: Int): Int = nums.sum()
val valores = intArrayOf(1, 2, 3)
sumAll(*valores) // ✅ correcto: desempaquetado con *
Kotlin optimiza los tipos primitivos (Int
, Double
, etc.) usando IntArray
, DoubleArray
, etc., en lugar de Array<Int>
o Array<Double>
.
Esto mejora el rendimiento y evita el boxing innecesario.
Ejercicio
Ejercicio de cierre: Duplicar niveles de poder
Vamos a practicar la declaración de funciones en Kotlin aplicando una transformación sobre una lista.
Supón que tienes una lista de niveles de poder (Int
) y quieres duplicar cada uno de ellos usando map
.
Como recordatorio, map
aplica una función a cada elemento de una colección y devuelve una nueva colección con los resultados:
fun <T, R> Iterable<T>.map(transform: (T) -> R): List<R>
fun IntArray.map(transform: (Int) -> R): List<R>
Tu tarea es definir una función llamada doublePowers
que reciba una lista de enteros (List<Int>
) o bien una cantidad variable de argumentos (vararg
) y devuelva una nueva lista con cada valor duplicado.
🎯 Conclusiones
En esta lección conocimos la sintaxis básica para declarar funciones en Kotlin, un componente esencial para estructurar código reutilizable, expresivo y mantenible. También exploramos algunas variantes idiomáticas como la inferencia de tipos, las funciones variádicas y la diferencia entre colecciones como Array
y List
.
🔑 Puntos clave
- Las funciones se declaran con la palabra clave
fun
y pueden tener parámetros con valores por defecto. - El tipo de retorno puede inferirse automáticamente si la función se reduce a una sola expresión.
vararg
permite definir funciones que aceptan una cantidad variable de argumentos.- Es posible requerir al menos un argumento junto a
vararg
, combinándolos en la firma. Array<T>
yList<T>
parecen similares, pero tienen diferencias clave en mutabilidad y uso.- Kotlin favorece un estilo conciso, pero también explícito y claro cuando la función es pública o compleja.
🧰 ¿Qué nos llevamos?
Esta lección es una primera aproximación al sistema de funciones de Kotlin.
No necesitas memorizar todos los detalles ahora: puedes volver a este material como referencia rápida.
A lo largo del curso, retomaremos estos conceptos y profundizaremos en los aspectos más relevantes según el contexto de cada unidad.
En otros lenguajes
📖 ¿Con ganas de más?
🔥 Referencias recomendadas
- 🌐 “Funciones | Kotlin” en Kotlin docs:Esta documentación ofrece una guía exhaustiva sobre la declaración y uso de funciones en Kotlin. Aborda desde conceptos básicos como la sintaxis con
fun
, el uso de parámetros con tipo explícito y valores por defecto, hasta temas más avanzados como funciones variádicas (vararg
), argumentos nombrados, funciones de una sola expresión, inferencia de tipos, funciones infijas (infix
), genéricas y recursivas de cola (tailrec
). También detalla cómo declarar funciones a nivel superior, funciones locales, de miembro y de extensión, promoviendo un estilo conciso, idiomático y expresivo. Es una fuente esencial para comprender el modelo funcional y flexible de funciones en Kotlin.
Footnotes
-
El principio get-put establece que un tipo covariante puede ser usado como un tipo de retorno (
out
) pero no como un tipo de entrada (in
). En este caso,out
indica que el arreglo solo se usa para obtener valores, no para insertarlos. ↩ -
Se llama azúcar sintáctica (syntactic sugar) a una forma más conveniente o legible de escribir algo que, en realidad, se traduce a una forma más básica del lenguaje. ↩