En Rust, los closures son funciones anónimas que pueden "capturar" variables del ámbito externo. Sintaxis:
let add = |a: i32, b: i32| a + b;
En Rust hay tres tipos de closures (difieren en la forma en que capturan variables):
&T), se puede invocar múltiples veces sin mutar el entorno.&mut T), se pueden modificar los datos del closure al invocarlo.T).Rust determina automáticamente el tipo necesario, pero puedes especificarlo explícitamente.
Ejemplo de diferencias:
let s = String::from("hello"); // FnOnce let consume = move || println!("{}", s); // s ya no está disponible después de la llamada
¿Por qué un closure con la palabra clave move puede no ser FnOnce, sino Fn o FnMut?
Respuesta: La palabra clave move transfiere la captura de variables por propiedad, pero si los datos dentro del closure no son mutados ni destruidos, el closure sigue siendo compatible con Fn/FnMut. Por ejemplo:
let s = String::from("abc"); let c = move || println!("String: {}", s); // c: impl Fn() c();
c se puede invocar múltiples veces: el valor de s se copió en el closure, pero no se destruyó.
Historia
Un desarrollador principiante de Rust en un proyecto con flujos de datos intentó escribir un closure sin move, pasándolo a otro hilo. Como resultado, el compilador se quejaba de un outlived borrow, y tuvo que apresurarse a entender los matices de lifetime y move.
Historia
Introdujeron mutabilidad dentro del closure, sin cambiar el tipo a FnMut, lo que causó "mismatched types" en todos los lugares donde se utilizaba el iterador.
Historia
Al procesar un gran arreglo, el closure movió toda la colección sin darse cuenta, lo que resultó en que el código externo perdiera acceso a los datos después de la primera iteración, causando intentos de acceder a un moved value.