Curso Kotlin | #16. Funciones

Las funciones son procedimientos que se pueden reutilizar y nos permiten encapsular comportamientos y mejorar la lectura del código.

Estructura

En todos nuestros ejemplos anteriores, escribimos el código en la función main:

fun main(args: Array<String>) {

Analicemos la estructura, señalando cada parte de la misma:

fun nombre(parametros: Tipo){
    // cuerpo
}

Toda función debe iniciar con la palabra reservada fun y luego continuar con su nombre. Entre paréntesis puede ir uno o más parámetros, pero también puede no tenerlos. Cada parámetro debe tener su tipo declarado; y dentro de las llaves (al igual que pasaba con la sentencia If) tendremos el cuerpo de la función, su comportamiento.

Nuestra función main contiene un Array de Strings porque nos permite decirle a Intellij que enviaremos parámetros por consola a la hora de ejecutar la aplicación. Ten esto en cuenta, pero no profundicemos todavía, dado que va a confundirte el uso particular de esta función.

Nuestra primer función

¿Recuerdas el ejemplo de la clase anterior?:

print("Cual es tu nombre? >")
val name = readLine()

if(name.isNullOrEmpty()){
    throw Exception("El nombre no puede estar vacío!")
} else {
    print("Hola $name!")
}

Ahora imagina que quiero utilizar dos veces este algoritmo: quiero preguntar dos nombres e imprimirlos en pantalla si todo salió bien. Vamos a crear una función (fuera de main) y encapsular todo el contenido del ejemplo anterior:

fun sayMyName() {
    print("Cual es tu nombre? >")
    val name = readLine()

    if(name.isNullOrEmpty()){
        throw Exception("El nombre no puede estar vacío!")
    } else {
        print("Hola $name!")
    }
}

Una vez declarada la función, veremos que el texto se vuelve gris:

Esto significa que no se está llamando en ningún lado, por lo cual lo vamos a solucionar en la función main:

fun main(args: Array<String>) {
    sayMyName()
    sayMyName()
}

La llamamos dos veces porque queremos preguntar por dos nombres. Nuestra función cumple su utilidad, pero vamos a volverla más flexible.

Es hora de usar parámetros

Los parámetros en una función nos van a permitir obtener distintos resultados en base a la información que enviemos. Vamos a pasar el nombre por parámetro:

fun sayMyName(name: String?) {

Recuerda que el tipo tiene que ser String nullable porque vamos a enviarle el resultado de readLine.

fun main(args: Array<String>) {
    print("Cual es tu nombre? >")
    val name = readLine()

    sayMyName(name)
}

fun sayMyName(name: String?) {
    if(name.isNullOrEmpty()){
        throw Exception("El nombre no puede estar vacío!")
    } else {
        print("Hola $name!")
    }
}

Nos conviene que la función sayMyName no contenga código del input, porque ahora podemos usarla para cualquier tipo de entrada. Por ejemplo podríamos llevarnos esa función a un botón que la dispare en el momento de presionarlo, leyendo un campo de texto, como en un formulario.

Retorno de una función

Una función que imprima nuestro nombre en pantalla esta bien, pero ¿qué ocurre si quiero guardar el resultado en una variable y utilizarla en otro lugar?. Necesitamos que nuestra función retorne la misma:

fun sayMyName(name: String?): String {

Al escribir “: Tipo” luego de los paréntesis de nuestra función, declaramos el retorno de la misma. Anteriormente no necesitábamos esto porque nuestra función no tenía retorno (el famoso void de Java), pero ahora requerimos devolver un String:

fun sayMyName(name: String?): String {
    if(name.isNullOrEmpty()){
        throw Exception("El nombre no puede estar vacío!")
    }
    
    return "Hola $name!"
}

He removido el else del condicional para limpiar un poco el código, pero el resultado es el mismo. Quité el print y lo convertí en un “return [string]”. Si ejecutamos el programa ahora mismo, no nos devolverá nada porque tenemos una función que devuelve un valor, el cual no se esta guardando ni tampoco imprimiendo. Vamos a arreglar eso:

val output = sayMyName(name)
println(output)

Podemos simplificar todo en una linea si no queremos reutilizar la salida:

println(sayMyName(name))

Valor por Defecto

Kotlin nos permite definir valores por defecto en una función. Esto en Java no existía y teníamos que simularlo a través de la sobreescritura de métodos, algo que veremos mucho más adelante.

Vamos a definir un valor para name cuando no se ingrese nada en consola:

fun sayMyName(name: String? = "Maxwell"): String {

Esto nos permite llamar a la función sin enviar un parámetro:

println(sayMyName())

Esto nos va a devolver “Hola Maxwell!”. No existe un límite en la cantidad de parámetros por defecto que queramos agregar.

Funciones Inline

Si el cuerpo de la función solo posee una linea, podemos utilizar funciones inline. Por ejemplo, implementemos una funcion que sume dos números y los retorne:

fun sum(num1: Int, num2: Int): Int {
    return num1 + num2
}

Por supuesto no hay nada mal en esta función, pero podemos implementarla como una inline function:

fun sum(num1: Int, num2: Int): Int = num1 + num2

Como habrán notado, se quita el return porque al escribir el signo de igualdad, Kotlin infiere que se trata de una inline function y lo que siga después es parte de su retorno. Esta forma se utiliza muchísimo, especialmente cuando entremos en el terreno de la programación orientada a objetos.

Conclusiones

Las funciones nos acompañarán a lo largo de todo el resto de la serie del curso de Kotlin. Es fundamental comprender su funcionamiento e implementación dado que nos darán una flexibilidad mayor en las próximas entregas.

¡Deja un comentario!

Artículos relacionados

Curso Kotlin | #19. Pair

A veces necesitamos relacionar dos valores y almacenarlos en una variable única, y para ello tenemos a Pair.

Curso Kotlin | #17. Proyecto: The Hero Legacy

Si empezaste esta serie desde cero y ya leíste 16 capítulos, ¡Felicidades! Empezaste a dominar los primeros conceptos fundamentales en Kotlin. Este es el primer paso de tu senda como desarrollador/a. Estamos en una instancia en donde podemos poner en práctica todo lo que aprendiste hasta ahora. Bienvenido/a al primer proyecto de la serie.

Curso Kotlin | #15. Excepciones

Las excepciones en Kotlin nos permiten evitar comportamientos no deseados ante problemas que se presentan en tiempo de ejecución. Por ejemplo cuando se intenta dividir por cero, castear un tipo por otro no válido, intentar agregar un valor a una lista nula, entre otros casos. Hoy vamos a ver su implementación en el código.

Curso Kotlin | #14. Rangos

Cuando hablamos de rangos, nos referimos a un intervalo de números en el sentido matemático. Podemos generar, por ejemplo, un rango que comprenda los números del 1 al 10. Hoy veremos como aplicarlo a los conceptos anteriormente aprendidos.

Curso Kotlin | #13. Bucle For

El bucle For es uno de los más utilizados por todos los lenguajes de programación. Nos permite recorrer arrays y listas, como también generar iteraciones con un límite contabilizado. Vamos a verlo en detalle.