Introducción
En este laboratorio, exploramos los closures, que son funciones en Rust que pueden capturar el entorno circundante al hacer referencia a variables fuera de su ámbito.
Nota: Si el laboratorio no especifica un nombre de archivo, puede usar cualquier nombre de archivo que desee. Por ejemplo, puede usar
main.rs, compilar y ejecutarlo conrustc main.rs &&./main.
Closures
Los closures son funciones que pueden capturar el entorno circundante. Por ejemplo, un closure que captura la variable x:
|val| val + x
La sintaxis y las capacidades de los closures los hacen muy convenientes para su uso inmediato. Llamar a un closure es exactamente como llamar a una función. Sin embargo, tanto los tipos de entrada como de retorno pueden ser inferidos y los nombres de las variables de entrada deben ser especificados.
Otras características de los closures incluyen:
- usar
||en lugar de()alrededor de las variables de entrada. - delimitación opcional del cuerpo (
{}) para una sola expresión (obligatoria en caso contrario). - la capacidad de capturar las variables del entorno externo.
fn main() {
let outer_var = 42;
// Una función regular no puede hacer referencia a variables en el entorno circundante
//fn function(i: i32) -> i32 { i + outer_var }
// TODO: descomentar la línea anterior y ver el error del compilador. El compilador
// sugiere que definamos un closure en lugar.
// Los closures son anónimos, aquí los estamos enlazando a referencias
// La anotación es idéntica a la anotación de función pero es opcional
// al igual que las `{}` que envuelven el cuerpo. Estas funciones sin nombre
// se asignan a variables con nombres adecuados.
let closure_annotated = |i: i32| -> i32 { i + outer_var };
let closure_inferred = |i | i + outer_var ;
// Llama a los closures.
println!("closure_annotated: {}", closure_annotated(1));
println!("closure_inferred: {}", closure_inferred(1));
// Una vez que el tipo de un closure ha sido inferido, no se puede inferir de nuevo con otro tipo.
//println!("cannot reuse closure_inferred with another type: {}", closure_inferred(42i64));
// TODO: descomentar la línea anterior y ver el error del compilador.
// Un closure que no toma argumentos y devuelve un `i32`.
// El tipo de retorno es inferido.
let one = || 1;
println!("closure returning one: {}", one());
}
Resumen
¡Felicitaciones! Has completado el laboratorio de Closures. Puedes practicar más laboratorios en LabEx para mejorar tus habilidades.