Como sabemos, una función es un pedazo de código que debería encargarse de una tarea específica, por ejemplo, calcular un impuesto, procesar un archivo o regresarme información de una tabla en de la base de datos, esto obviamente facilita la lectura del programa y permite que el código pueda ser mantenido de manera sencilla. En este post revisamos las funciones en Rust.
Puedes consultar los otros posts aquí:
La función main
es el punto de entrada principal, es decir, cuando ejecutemos o compilemos, se ejecutará lo que está dentro de ella. Su declaración es:
fn main() {
println!("Hello, world!");
another_function();
}
fn another_function() {
println!("Another function.");
}
En este código vemos que las funciones se declaran con el keyword fn
, que nos indica que se va a declarar una función.
También, por convención, las funciones se declara con snakecase
, es decir, se usan guiones bajos para nombrarlas, por ejemplo: mi_funcion
o calcular_impuesto_iva
.
También notamos que another_function
está declarada después que el bloque main
. Es decir, parece que estamos llamando a esta función antes de que sea declarada. En Rust, esto no es importante. Siempre y cuando las funciones estén declaradas en el mismo scope
, pueden estar declaradas en cualquier lugar. Esto no pasa con las variables, en este caso sí tienen que estar en orden, primero declaramos y luego las usamos.
¿Qué es scope
?
Seguramente ya lo sabes, pero que no quede duda. El scope
en pocas palabras es el espacio o bloque de código en donde las variables pueden ser llamadas y usadas. Por ejemplo, en nuestro código anterior, si declaras una variable dentro del bloque main
, no podrá ser usada en another_function
aunque esté llamada dentro de la otra. Puedes enviar un valor en caso de que lo recibiera, pero sería una variable totalmente diferente.
Parámetros de funciones en Rust
Los parámetros son aquellos valores que una función usa para realizar el proceso para el que está programada. En su declaración (signature
) debemos especificar estos valores que va a recibir:
fn main() {
another_function(50);
}
fn another_function(x: i32) {
println!("The value of x is: {x}");
}
En esta modificación, vemos que another_function
se declara con el “parámetro” (esta palabra se usa en la declaración, para el valor que se va a recibir) x
de tipo entero de 32 bits con signo (puede ser negativo o positivo) i32
. Y dentro de main
la llamamos con enviando el argumento (este palabra se usa para el valor enviado) 50
.
También podemos enviarle más de un argumento a una función, esto se hace declarando los parámetros separados por comas:
fn main() {
print_labeled_measurement(5, 'h');
}
fn print_labeled_measurement(value: i32, unit_label: char) {
println!("The measurement is: {value}{unit_label}");
}
Como vemos, los parámetros no deben ser del mismo tipo. Solo deben estar separados por come y declara explícitamente el tipo que se va recibir.
Funciones en Rust que regresan valor
Obviamente, las funciones en Rust no tendrían sentido si solo imprimieran valores por pantalla, el objetivo es que puedan procesar información y regresar la información relevante.
En Rust se declara de la siguiente manera:
fn five() -> i32 {
5
}
fn main() {
let x = five();
println!("The value of x is: {x}");
}
Como vemos, usamos el operador ->
seguido del tipo de dato para indicarle que ese será el valor que va a regresar. Acá no usamos nombre, solamente el tipo.
Otra cosa ¿se nos olvidó el return
? No, en Rust así es como se regresan los valores. Esto tiene que ver con la forma en que Rust evalúa las expressions
y los statements
. Revisemos un poco estos valores:
Expressions y Statements
Las expresiones o expressions
son bloques de código que evalúan y regresan valores y por lo tanto pueden ser usados de la forma en la que vemos en el bloque de código anterior de la función.
fn main() {
let x = (let y = 6);
}
¿Recuerdan algún tipo de declaración de este tipo: y = x = 10
? (aquí y
y x
tienen el valor 10
)Pues digamos que este ejemplo es el que estamos emulando en nuestro código. Sin embargo, acá no es válido. En Rust esto sería un statement
, no una expression
. Es decir, la declaración de una variable no regresa un valor.
Un statement
sería una declaración de una función o una variable. Esto no regresa un valor, simplemente ejecuta algo. Aquí entran las declaraciones de una variable, el uso de los ciclos o control de flujo.
Para completar el código anterior de manera que tenga sentido para Rust, lo hacemos de la siguiente manera:
fn main() {
let y = {
let x = 3;
x + 1
};
println!("The value of y is: {y}");
}
Aquí ya vemos que dentro del bloque de código que le asignamos a y
, creamos la variable x
con valor 3
, luego le sumamos 1
y hasta ahí llega el código, cuyo “return” es muy parecido a nuestra función five
. ¿Vemos algo raro? Pues que la línea que regresa el valor no tiene punto y coma ;
, como todo lo demás.
Entonces, para integrar todo lo que hemos aprendido, hagamos una comparación.
Escribimos esta función:
fn main() {
let x = plus_one(5);
println!("The value of x is: {x}");
}
fn plus_one(x: i32) -> i32 {
x + 1
}
y hacemos cargo run
. Veremos que compila bonito.
Ahora escribamos esto:
fn main() {
let x = plus_one(5);
println!("The value of x is: {x}");
}
fn plus_one(x: i32) -> i32 {
x + 1;
}
¡¡¡ERRORES!!! ¿Qué son?
En la función plus_one
la línea que debería regresarnos el valor, tiene punto y coma. Rust nos indica que para resolverlo, lo quitemos.
Estas fueron las funciones en Rust.
Puedes consultar más en https://doc.rust-lang.org/book/ch03-03-how-functions-work.html
Gracias por leer.