Saltar al contenido
K
Kotlin: el lenguajePaso a paso30 min de lectura · 8 min de máquina Básico

Funciones y parámetros

Al terminar: Escribir funciones con parámetros, valor de retorno y argumentos por nombre, y la diferencia entre devolver e imprimir.

Al terminar sabrás escribir una función (un bloque de código con nombre que recibe datos y devuelve un resultado) y llamarla. Con eso tendrás el primer trozo del torneo en código: encabezadoDeJornada(numero, totalDeJornadas), que escribe un texto como «Jornada 2 de 5».

Importa porque cualquier programa, del tamaño que sea, está hecho de funciones pequeñas que se llaman unas a otras.

Temas: funciones, parámetros, valor de retorno, valores por defecto y argumentos con nombre. En la lección siguiente, Condiciones: if y when, harás que el programa decida con preguntas de sí o no.

Qué es una función

Hasta ahora todo tu código ha ido dentro de main, que ya es una función. Una función es un bloque de instrucciones con nombre: lo escribes una vez y lo usas todas las veces que quieras, sin copiarlo. Sirve para dos cosas: no repetir código y poner nombre a una idea («calcular el área», «saludar») para que el programa se lea como una frase.

Dos palabras que vas a usar mucho: llamar a una función es pedirle que se ejecute (escribes su nombre y, entre paréntesis, los argumentos), y devolver es entregar un resultado a quien la llamó. Ya has llamado a una: println("Hola") es una llamada a la función println con el argumento "Hola".

ejemplo mínimo: escribir y llamar funciones (con comentarios)
// Una función es un bloque de instrucciones con nombre: se escribe una vez y se usa las veces que haga falta
fun saludar(nombre: String) {          // nombre es un parámetro: el hueco que se rellena al llamarla
    println("Hola, $nombre")           // $nombre mete el valor del parámetro en el texto
}
 
// Esta devuelve un resultado: «: Int» dice de qué tipo es, y return lo entrega
fun areaDelRectangulo(ancho: Int, alto: Int): Int {
    val area = ancho * alto            // variable local: se crea aquí dentro y solo se puede usar dentro de esta función
    return area                        // return entrega el resultado a quien la llamó y termina la función
}
 
fun main() {
    saludar("Ana")                     // llamar a la función: su nombre y, entre paréntesis, el argumento ("Ana")
    saludar("Luis")                    // la misma función con otro argumento
    val area = areaDelRectangulo(3, 4) // el resultado devuelto se puede guardar en una variable
    println(area)                      // 12
    println(areaDelRectangulo(5, 2))   // 10: o usarlo directamente
    println("El área es ${areaDelRectangulo(3, 4)} y la mitad es ${area / 2}")   // ${…} mete en el texto el resultado de una cuenta o de una llamada
}
Hola, Ana
Hola, Luis
12
10
El área es 12 y la mitad es 6

Dentro de un texto, $nombre mete el valor de una variable. Si lo que quieres meter no es un nombre solo sino una cuenta o una llamada a una función, la escribes entre llaves: ${area / 2}. Lo que haya dentro de las llaves se calcula y su resultado pasa a formar parte del texto.

return entrega el resultado de la función a quien la llamó y la termina en ese punto: lo que haya debajo ya no se ejecuta.

Fíjate en area, dentro de areaDelRectangulo: es una variable local, una variable que se crea dentro de la función y solo existe mientras la función se ejecuta. Fuera de ella no se puede usar (en main hay otra area, distinta, que guarda el resultado).

Devolver no es imprimir

Es la confusión más común al empezar. println muestra algo en la pantalla; return entrega un valor al código que llamó a la función, que puede guardarlo, sumarlo o usarlo en otra cuenta. Una función puede imprimir sin devolver nada, y puede devolver sin imprimir nada:

ejemplo mínimo: imprimir frente a devolver (con comentarios)
fun imprimirDoble(x: Int) {            // imprime el doble, pero no devuelve nada
    println(x * 2)
}
 
fun doble(x: Int): Int {               // devuelve el doble, pero no imprime nada
    return x * 2
}
 
fun main() {
    imprimirDoble(4)                   // se ve 8 en pantalla, pero ese 8 no se puede guardar ni usar después
    val resultado = doble(4)           // aquí no se ve nada: el 8 queda guardado en la variable
    println(resultado + 1)             // 9: se puede seguir usando
}
8
9

Una función que no devuelve nada, como saludar o imprimirDoble, en realidad devuelve Unit, el «nada» de Kotlin, y no hace falta escribirlo ni poner return.

Funciones de una línea, valores por defecto y argumentos con nombre

Tres comodidades que verás en todo el torneo:

  • Función de expresión. Una expresión es un trozo de código que da un valor, como x * 2 (ya la conoces de Variables, tipos y operaciones). Si el cuerpo de la función es una sola, puedes quitar las llaves y el return: después del = va la expresión y su valor es lo que devuelve la función. El tipo de retorno se deduce solo, aunque puedes escribirlo igualmente (fun doble(x: Int): Int = x * 2); cuando el cuerpo es largo conviene escribirlo para que se lea mejor.
  • Valor por defecto. Un parámetro puede traer un valor ya puesto, como la «sal al gusto» de la receta: si al llamar no dices nada, se usa ese; si quieres otro, lo indicas.
  • Argumento con nombre. Al llamar, escribes prefijo = "Aviso" en lugar de pasar solo el valor. La llamada se lee sin tener que adivinar qué es cada dato, y puedes darlos en cualquier orden.
ejemplo mínimo: de expresión, por defecto y con nombre (con comentarios)
// De expresión: sin llaves ni return; después del = va una expresión y su valor es el resultado
fun doble(x: Int) = x * 2
 
// Con valor por defecto: si no pasas el prefijo, se usa "Nota"
fun etiqueta(texto: String, prefijo: String = "Nota") = "$prefijo: $texto"
 
fun main() {
    println(doble(5))                                           // 10
    println(etiqueta("traer agua"))                             // sin prefijo: usa el de por defecto
    println(etiqueta("traer agua", "Aviso"))                    // con prefijo, por posición
    println(etiqueta(prefijo = "Aviso", texto = "traer agua"))  // con nombre, en cualquier orden
}
10
Nota: traer agua
Aviso: traer agua
Aviso: traer agua

Resumen de las formas de escribir una función que ya has visto:

DetalleCómo se escribePara qué
Sueltafun escrita directamente en el fichero, como main, fuera de cualquier otra cosaUna función que no depende de nada más
De bloquefun area(a: Int, b: Int): Int { return a * b }Varias líneas; el tipo de retorno se escribe tras : y se devuelve con return
Sin resultado (Unit)fun saludar(n: String) { println(n) }Solo hace algo; no devuelve nada
Valor por defectoprefijo: String = "Jornada"Que el parámetro se pueda omitir
Argumento con nombreprefijo = "Fecha"Leer la llamada sin adivinar
De expresiónfun doble(x: Int) = x * 2Cuerpo de una sola expresión; el tipo de retorno se infiere (o se escribe tras :)

Reto · Ejercicio: la taquilla

En el Kotlin Playground (el mismo de Tu primer proyecto en Kotlin; no toques tu proyecto), escribe dos funciones. precioFinal recibe las entradas, el precio de cada una (si no se dice, 10) y el porcentaje de descuento (si no se dice, 0), y devuelve lo que se paga. Pista: primero multiplica entradas por precio y por 100 - descuento, y al final divide entre 100, para que la división entera no recorte antes de tiempo. mostrar recibe lo mismo, no devuelve nada e imprime «N entradas: » seguido del precio final. En main, llama a mostrar para 2 entradas, para 5 entradas con un 10 de descuento y para 5 entradas a precio 4, pasando el descuento y el precio por su nombre. La consola debe mostrar:

2 entradas: 20
5 entradas: 45
5 entradas: 20
Ver solución
solución del ejercicio
// De expresión, con dos valores por defecto. Primero se multiplica y al final se divide
fun precioFinal(entradas: Int, precio: Int = 10, descuento: Int = 0): Int =
    entradas * precio * (100 - descuento) / 100
 
// Sin resultado (Unit): imprime, no devuelve nada
fun mostrar(entradas: Int, precio: Int = 10, descuento: Int = 0) {
    println("$entradas entradas: ${precioFinal(entradas, precio, descuento)}")   // ${…}: el resultado de una llamada, dentro del texto
}
 
fun main() {
    mostrar(2)                      // usa el precio y el descuento por defecto
    mostrar(5, descuento = 10)      // el descuento, por su nombre
    mostrar(5, precio = 4)          // el precio, por su nombre
}

Paso · Puntos.kt y un Main.kt que lo usa

Objetivo: dos ficheros. Puntos.kt con el encabezado de jornada y un Main.kt que lo llama. Al terminar, ./gradlew :torneo:run imprime el nombre del torneo y los encabezados de sus jornadas. La regla de los puntos la añades en la lección siguiente.

torneo/
kotlin+java/
com.sebastiannarvaez.marcador.torneoel paquete que ya tienes
Puntos.ktse crea
Main.ktse modifica
Lo que tocas, en la vista Android.

1 · Crea Puntos.kt. En la vista Android, despliega torneo → kotlin+java. Haz clic derecho sobre el paquete com.sebastiannarvaez.marcador.torneo (donde está Main.kt) → New → Kotlin Class/File → File → escribe Puntos y pulsa Intro. Se abre Puntos.kt con la línea package ya escrita.

Piezas que vas a usar, todas de esta lección:

  • fun nombre(a: Int, b: Int): String = …: función de expresión; lo que va tras el = es lo que devuelve.
  • prefijo: String = "Jornada": parámetro con valor por defecto.
  • numero = 1: argumento con nombre.

Intenta escribirlo tú, en dos ficheros:

  • Puntos.kt: encabezadoDeJornada(numero, totalDeJornadas, prefijo) devuelve un texto como «Jornada 2 de 5»; el prefijo es opcional y, si no se da, es «Jornada».
  • Main.kt, que ya existe: sustituye todo su contenido. El programa presenta el torneo («Copa Barrio»), escribe el encabezado de las jornadas 1, 2 y 3 de 3 (con argumentos con nombre) y uno más con el prefijo «Fecha».

Al ejecutar ./gradlew :torneo:run debe verse:

Torneo: Copa Barrio
Jornada 1 de 3
Jornada 2 de 3
Jornada 3 de 3
Fecha 1 de 3

El título de cada bloque de abajo es la ruta del fichero en tu proyecto. En cada uno, selecciona todo (Cmd + A) y pega el bloque.

Intenta primero. Cuando termines, compara con la solución.Mostrar el código
torneo/src/main/java/com/sebastiannarvaez/marcador/torneo/Puntos.kt
package com.sebastiannarvaez.marcador.torneo
 
// Función suelta: escrita directamente en el fichero.
// Parámetros con valor por defecto: se pueden omitir al llamar.
fun encabezadoDeJornada(numero: Int, totalDeJornadas: Int, prefijo: String = "Jornada"): String =
    "$prefijo $numero de $totalDeJornadas"
torneo/src/main/java/com/sebastiannarvaez/marcador/torneo/Main.kt
package com.sebastiannarvaez.marcador.torneo
 
// Punto de entrada de consola: ./gradlew :torneo:run
fun main() {
    val nombreDelTorneo = "Copa Barrio"
    val totalDeJornadas = 3
    println("Torneo: $nombreDelTorneo")
 
    // Argumento con nombre: se lee sin adivinar qué es cada número.
    println(encabezadoDeJornada(numero = 1, totalDeJornadas = totalDeJornadas))
    println(encabezadoDeJornada(numero = 2, totalDeJornadas = totalDeJornadas))
    println(encabezadoDeJornada(numero = 3, totalDeJornadas = totalDeJornadas))
    println(encabezadoDeJornada(1, 3, prefijo = "Fecha"))
}

Lo que ves en Puntos.kt: encabezadoDeJornada es una función suelta y de expresión, con un parámetro opcional. Los argumentos con nombre de Main.kt (numero = 1) se leen sin abrir la función.

Punto de control

  • En la vista Android, el paquete com.sebastiannarvaez.marcador.torneo de torneo → kotlin+java contiene ahora Main.kt y Puntos.kt.
  • ./gradlew :torneo:run imprime las cinco líneas de arriba, de Torneo: Copa Barrio a Fecha 1 de 3.
  • Puntos.kt tiene una función de expresión con un valor por defecto. Todavía no hay tests (comprobaciones automáticas que escribirás en dos lecciones, en Bucles y tu primer test): no hay nada que contar hasta entonces.

Comprueba lo que entendiste

4 preguntas · necesitas 3 para completar la lección

  1. 1.Con fun encabezado(numero: Int, total: Int, prefijo: String = "Jornada"), ¿cuál de estas llamadas es válida?

  2. 2.Una función fun mostrarDoble(x: Int) { println(x * 2) } imprime el doble. ¿Qué pasa con val d = mostrarDoble(4)?

  3. 3.Con fun doble(x: Int) = x * 2, ¿qué muestra println(doble(5))?

  4. 4.¿Qué hace return dentro de una función?

Faltan 4 de 4