En Rust, les closures sont des fonctions anonymes qui peuvent "capturer" des variables de l'extérieur de leur portée. La syntaxe :
let add = |a: i32, b: i32| a + b;
Il existe trois types de closures en Rust (qui diffèrent par la méthode de capture des variables) :
&T), peut être appelée plusieurs fois sans modifier l'environnement.&mut T), peut modifier les données de la closure lors de l'appel.T).Rust détermine automatiquement le type nécessaire, mais vous pouvez le spécifier explicitement.
Exemple de différences :
let s = String::from("hello"); // FnOnce let consume = move || println!("{}", s); // s n'est plus accessible après l'appel
Pourquoi une closure avec le mot-clé move peut-elle ne pas être FnOnce, mais plutôt être Fn ou FnMut ?
Réponse : Le mot-clé move effectue la capture des variables par possession, mais si les données à l'intérieur de la closure ne sont pas modifiées ou détruites, la closure reste compatible avec Fn/FnMut. Par exemple :
let s = String::from("abc"); let c = move || println!("String: {}", s); // c: impl Fn() c();
c peut être appelée plusieurs fois : la valeur de s est copiée dans la closure, mais n'est pas détruite.
Histoire
Un développeur Rust débutant dans un projet avec des flux de données a essayé d'écrire une closure sans move, en la passant à un autre flux. En conséquence, le compilateur se plaignait d'un outlived borrow, et il a dû se plonger dans les subtilités des lifetimes et du move.
Histoire
Ils ont introduit de la mutabilité à l'intérieur de la closure, sans changer le type en FnMut, ce qui a causé des erreurs "mismatched types" à tous les endroits où ils utilisaient des itérateurs.
Histoire
Lors du traitement d'un grand tableau, la closure a pris possession par move de toute la collection, déplaçant involontairement la propriété, ce qui a conduit le code extérieur à perdre l'accès aux données après la première itération, entraînant des tentatives d'accès à des valeurs déplacées.