Las funciones son cuerpos de código que contienen una o más instrucciones o expresiones. Una función puede, de forma opcional, devolver un valor.
El estilo de Rust es usar snake case para el nombre de una función, que en la definición de la función va precedido por la palabra clave fn. Por ejemplo
fn do_nothing() {}
Los paréntesis rodean cero o más parámetros, separados por comas. Un parámetro es un enlace a un valor de un tipo concreto que se pasa a la función. Aunque no haya parámetros, los paréntesis siguen siendo necesarios en la definición de la función. El valor real que se pasa a un parámetro se llama argumento.
La combinación de parámetros y valor devuelto se conoce como la firma de la función. La firma de una función exige que cada parámetro tenga su tipo anotado.
Las llaves encierran el cuerpo de la función: sus instrucciones y expresiones. Aunque la función no contenga instrucciones ni expresiones, las llaves siguen siendo necesarias en la definición de la función.
En el siguiente ejemplo, la función recibe un parámetro de tipo i32, lo enlaza al nombre value y lo imprime.
fn print_integer(value: i32) {
println!("{value:?}");
}
Fíjate en la definición del parámetro. Cada parámetro se define con el formato name: Type.
Una función también puede devolver un valor. De forma predeterminada, se devuelve el resultado de la última expresión. En el siguiente ejemplo, la función tiene un parámetro i32 y devuelve su doble.
fn double_integer(value: i32) -> i32 {
value * 2
}
El -> i32 indica que la función devuelve un i32. A diferencia de los parámetros, el valor devuelto no tiene nombre.
Es posible salir antes de una función con la palabra clave return, así:
fn long_function() -> i32 {
let some_condition = false;
// code snipped
if (some_condition) {
return 0;
}
// more code snipped
42
}
const fn se usa para definir una función constante, que puede evaluarse en tiempo de compilación.
const fn compute_data_checksum() -> u128 {
const DATA: &[u8] = include_bytes!("my_big_data_file");
// checksum implementation is left as an exercise for the reader
}
/// This checksum is used to validate that the user has not tampered with proprietary configuration.
pub const DATA_CHECKSUM: u128 = compute_data_checksum();
Como las funciones constantes pueden evaluarse en tiempo de compilación, tienen algunas restricciones que las funciones normales no tienen. En particular, una const fn solo puede llamar a otras funciones que también estén marcadas como const. Incumplir esa restricción provoca un error de compilación.
const fn multiply_integer(value: i32) -> i32 {
use std::time::SystemTime;
if SystemTime::now().elapsed().unwrap().as_nanos() == 0 { // this line errors
value * 2
} else {
value * 3
}
}
Existen funciones anónimas, que se tratan en el tema closures.