Volver a Kotlin Básico

Introducción

Las funciones en Kotlin son más poderosas que en Java, con soporte para parámetros por defecto, argumentos con nombre y funciones de extensión que te permiten agregar funcionalidad a clases existentes.

Funciones Básicas

// Función simple fun saludar(nombre: String) { println("¡Hola, $nombre!") } // Función con tipo de retorno fun sumar(a: Int, b: Int): Int { return a + b } // Función de expresión única fun multiplicar(a: Int, b: Int) = a * b // Tipo de retorno Unit (como void en Java) fun imprimirSuma(a: Int, b: Int): Unit { println("Suma: ${a + b}") }

Parámetros por Defecto

fun crearUsuario( nombre: String, edad: Int = 18, pais: String = "Desconocido" ) { println("Usuario: $nombre, $edad, $pais") } // Uso crearUsuario("Alicia") // Usa valores por defecto crearUsuario("Bob", 25) // Sobrescribe edad crearUsuario("Carlos", 30, "USA") // Sobrescribe todos

Argumentos con Nombre

fun enviarEmail( para: String, asunto: String, cuerpo: String, cc: String = "", cco: String = "" ) { println("Para: $para, Asunto: $asunto") } // Llamada con argumentos con nombre enviarEmail( para = "[email protected]", asunto = "Reunión", cuerpo = "Reunámonos mañana", cc = "[email protected]" )

Funciones de Extensión

Agrega métodos a clases existentes sin herencia:

// Extender clase String fun String.esPalindromo(): Boolean { return this == this.reversed() } // Uso println("anilina".esPalindromo()) // true println("hola".esPalindromo()) // false // Extender Int fun Int.esPar() = this % 2 == 0 fun Int.esImpar() = this % 2 != 0 println(4.esPar()) // true println(7.esImpar()) // true

Funciones Infijas

Crea código más legible similar a DSL:

infix fun Int.veces(str: String) = str.repeat(this) // Uso val resultado = 3 veces "Hola " // "Hola Hola Hola " // Funciones infijas incorporadas val par = "clave" to "valor" // to es una función infija val rango = 1 until 10 // until es una función infija

Funciones de Orden Superior

Funciones que toman funciones como parámetros o retornan funciones:

// Función como parámetro fun operarConNumeros(a: Int, b: Int, operacion: (Int, Int) -> Int): Int { return operacion(a, b) } // Uso val suma = operarConNumeros(5, 3) { x, y -> x + y } val producto = operarConNumeros(5, 3) { x, y -> x * y } // Función que retorna función fun crearMultiplicador(factor: Int): (Int) -> Int { return { numero -> numero * factor } } val duplicador = crearMultiplicador(2) println(duplicador(5)) // 10

Expresiones Lambda

// Sintaxis lambda val cuadrado: (Int) -> Int = { x -> x * x } val suma: (Int, Int) -> Int = { a, b -> a + b } // Parámetro único puede usar 'it' val doble: (Int) -> Int = { it * 2 } // Lambda multi-línea val calcular = { a: Int, b: Int -> val resultado = a + b resultado * 2 // Última expresión se retorna }

Funciones de Ámbito

let - Ejecutar código en no nulo:

val nombre: String? = "Alicia" nombre?.let { println("Longitud: ${it.length}") println("Mayúsculas: ${it.uppercase()}") }

apply - Configurar objetos:

val persona = Persona().apply { nombre = "Alicia" edad = 25 pais = "USA" }

also - Realizar efectos secundarios:

val numeros = mutableListOf(1, 2, 3) .also { println("Original: $it") } .add(4)

run - Ejecutar bloque de código:

val resultado = run { val a = 5 val b = 10 a + b // Retorna 15 }

with - Llamar múltiples métodos:

val mensaje = with(StringBuilder()) { append("Hola") append(" ") append("Mundo") toString() }

Ejemplos Prácticos

Procesamiento de listas:

val numeros = listOf(1, 2, 3, 4, 5, 6, 7, 8, 9, 10) // Filtrar y mapear val cuadradosPares = numeros .filter { it.esPar() } .map { it * it } // [4, 16, 36, 64, 100] // Operaciones personalizadas fun List<Int>.sumaDeCuadrados() = this.map { it * it }.sum() println(numeros.sumaDeCuadrados()) // 385

Extensiones de String:

fun String.truncar(longitudMaxima: Int): String { return if (this.length <= longitudMaxima) this else "${this.substring(0, longitudMaxima)}..." } println("Hola Mundo".truncar(5)) // "Hola..." fun String.aTituloCapitalizado() = this.split(" ") .joinToString(" ") { it.capitalize() } println("hola mundo".aTituloCapitalizado()) // "Hola Mundo"

Validación con extensión:

fun String.esEmailValido() = this.contains("@") && this.contains(".") fun String.esNombreUsuarioValido() = this.length >= 3 && this.all { it.isLetterOrDigit() || it == '_' } val email = "[email protected]" if (email.esEmailValido()) { println("Email válido") }

Buenas Prácticas

  • Usa funciones de extensión para agregar métodos de utilidad
  • Prefiere funciones de expresión única cuando sea posible
  • Usa argumentos con nombre para mejor legibilidad
  • Usa parámetros por defecto para reducir sobrecarga
  • Mantén las expresiones lambda cortas y legibles
  • Usa funciones de ámbito apropiadamente

Conclusión

Las características de funciones de Kotlin hacen el código más conciso y expresivo. Las funciones de extensión son particularmente poderosas para agregar funcionalidad sin modificar clases existentes.

En el próximo capítulo, exploraremos la seguridad de nulos en Kotlin.