Primeros pasos en Rust - Funciones

Apuntes de Rust - Parte 4

Table of contents

Funciones

Al igual que en muchos lenguajes de programación, además de la función main, en Rust podemos declarar nuevas funciones utilizando la palabra reservada fn. Ejemplo:

fn main() {
    println!("Hola, Mundo!");
    otra_funcion();
} 
fn otra_funcion() {
    println!("Hola, desde otra funcion.");
}

Se define una función en Rust usando fn seguido del nombre de la función y un conjunto de paréntesis. Las llaves indican al compilador dónde comienza y termina el cuerpo de la función.

Para invocar una función que hayamos definido, en el punto de llamado especificamos su nombre seguido de un conjunto de paréntesis. Como otra_funcion está definida en el programa, puede ser llamada desde dentro de la función main.

En Rust, se pueden pasar parámetros a una función de manera similar a otros lenguajes de programación. Los parámetros se definen dentro de los paréntesis de la declaración de la función.

Ejemplo:

fn saludar(nombre: &str) {
    println!("Hola, {}!", nombre);
}

fn main() {
    let nombre = "Jesse";
    saludar(nombre);
}

La función saludar recibe un parámetro nombre de tipo &str, que representa una referencia a una cadena. La función imprime un saludo utilizando el valor del parámetro.

En la función main, se crea una variable nombre con el valor "Jesse". Luego, se llama a la función saludar pasando el valor de nombre como argumento.

Se pueden definir múltiples parámetros separándolos por comas dentro de los paréntesis. Se debe especificar el tipo de cada parámetro utilizando la sintaxis nombre: tipo.

fn area_rectangulo(base: i32, altura: i32) -> i32 {
    let resultado = base * altura;
    resultado
}

fn main() {
    let base_rectangulo = 2;
    let altura_rectangulo = 3;
    let area = area_rectangulo(base_rectangulo, altura_rectangulo);

    println!("El área de un rectángulo de base {} y altura {} es {}", 
              base_rectangulo, altura_rectangulo, area);
}

En las firmas de las funciones, debe declarar el tipo de cada parámetro. Esta es una decisión deliberada en el diseño de Rust. Al requerir anotaciones de tipo en las definiciones de funciones, el compilador casi nunca va a requerir que especifique los tipos, otras partes del código. El compilador también puede proporcionar mensajes de error útiles si conoce los tipos que la función espera.

En este ejemplo, la función area_rectangulo recibe dos parámetros: base de tipo i32 y altura de tipo i32. El resultado es igual a la multiplicación de base por la altura, se almacena en la variable resultado y se devuelve al final de la función.

En la función main, se definen los valores de base_rectangulo y altura_rectangulo. Luego, se llama a la función area_rectangulo pasando estos valores como argumentos y se almacena el resultado en la variable area. Por último, se imprime el resultado utilizando la macro println!.

Como dato interesante, la función no especifica un return, en Rust, puede utilizar la palabra clave return para devolver un valor desde una función. Sin embargo, en Rust, también se puede omitir explícitamente el uso de return al final de una función para devolver el valor de la última expresión evaluada.

fn area_rectangulo_v1(base: i32, altura: i32) -> i32 {
    let resultado = base * altura;
    resultado // Sin utilizar la palabra clave 'return'
}

fn area_rectangulo_v2(base: i32, altura: i32) -> i32 {
    let resultado = base * altura;
    return resultado; // Se utiliza la palabra clave 'return'
}

fn main() {
    let base_rectangulo = 2;
    let altura_rectangulo = 3;
    let area1 = area_rectangulo_v1(base_rectangulo, altura_rectangulo);
    let area2 = area_rectangulo_v2(base_rectangulo, altura_rectangulo);

    println!("El área de un rectángulo de base {} y altura {} es {}", 
              base_rectangulo, altura_rectangulo, area1);

    println!("El área de un rectángulo de base {} y altura {} es {}", 
              base_rectangulo, altura_rectangulo, area2);
}

Para definir funciones que pueden retornar valores al código que las invoca. No nombramos los valores de retorno, pero debemos declarar su tipo después de una flecha (->) en firma de la función.

Podemos generalizar la estructura de una función en Rust de la siguiente forma:

fn nombre_de_la_funcion(parametro1: tipo1, parametro2: tipo2, ...) -> tipo_de_retorno {
    // cuerpo de la función
}

En Rust, el valor de retorno de la función es sinónimo del valor de la expresión final en el bloque del cuerpo de la función, por esta razón, no es necesario que se haga explícita la palabra clave return.

fn area_rectangulo_v1(base: i32, altura: i32) -> i32 {
    let resultado = base * altura;
    resultado // Sin utilizar la palabra clave 'return'
}

Como podemos observar en el ejemplo del área del rectángulo, la en la firma de la función, podemos ver luego del paréntesis una flecha indicando que la función retorna un valor de tipo i32.

Referencias

  • The Rust Programming Language. 2nd Edition by Steve Klabnik and Carol Nichols, with contributions from the Rust Community. 2023

Did you find this article valuable?

Support Jesse Padilla by becoming a sponsor. Any amount is appreciated!