Est-il possible de gérer plusieurs erreurs différentes à la fois plutôt qu'individuellement dans Rust sans utiliser de fonctions supplémentaires ? En bref: quel est l'équivalent de Rust d'une instruction try-catch?
Une fonctionnalité comme celle-ci ( gestion des erreurs de première classe avec ?
Et catch
) a été suggérée en 2016, mais je ne peux pas dire ce qui en est sorti et à quoi pourrait ressembler une solution 2019 pour un tel problème.
Par exemple, faire quelque chose comme ceci:
match do_steps() { Ok(_) => (), _ => alert_user("Failed to perform necessary steps") } // Additional function: fn do_steps() -> Result<(), Error>{ do_step_1()?; do_step_2()?; do_step_3()?; // etc Ok(()) }
Au lieu de:
try { do_step_1()?; do_step_2()?; do_step_3()?; // etc } catch { alert_user("Failed to perform necessary steps"); }
Mon programme a une fonction qui vérifie une variété d'endroits différents dans le registre pour différentes valeurs de données et renvoie des données agrégées. Il aurait besoin d'utiliser plusieurs de ces instructions try-cache avec try-catch à l'intérieur d'autres try-catch à l'intérieur des boucles.
3 Réponses :
Il n'y a pas d'instruction try catch dans Rust. L'approche la plus proche est le ?
opérateur.
Cependant, vous n'avez pas besoin de créer une fonction et une instruction de match
pour le résoudre à la fin. Vous pouvez définir une fermeture dans votre périmètre et utilisation ?
opérateur à l'intérieur de la fermeture. Ensuite, les lancers sont conservés dans la valeur de retour de fermeture et vous pouvez l'attraper où vous voulez, comme suit:
fn main() { let do_steps = || -> Result<(), MyError> { do_step_1()?; do_step_2()?; do_step_3()?; Ok(()) }; if let Err(_err) = do_steps() { println!("Failed to perform necessary steps"); } }
Est-il possible de gérer plusieurs erreurs différentes à la fois plutôt qu'individuellement dans Rust sans utiliser de fonctions supplémentaires?
Oui c'est possible. Il existe une caisse d' échec pour la gestion des erreurs dans Rust. En utilisant Failure
, vous pouvez chaîner, convertir, concaténer les erreurs. Après avoir converti les types d'erreur en un type commun, vous pouvez facilement l'attraper (le gérer).
Juste pour intervenir, mais l' failure
n'est pas la seule caisse qui aide à la gestion des erreurs. Il y en a beaucoup, chacun avec un objectif différent.
Notez que votre expression de fermeture est exactement ce que le bloc try
est destiné à être utilisé .
Result
dans Rust peuvent être chaînés en utilisant and_then
. Vous pouvez donc faire ceci:
macro_rules! attempt { // `try` is a reserved keyword (@recurse ($a:expr) { } catch ($e:ident) $b:block) => { if let Err ($e) = $a $b }; (@recurse ($a:expr) { $e:expr; $($tail:tt)* } $($handler:tt)*) => { attempt!{@recurse ($a.and_then (|_| $e)) { $($tail)* } $($handler)*} }; ({ $e:expr; $($tail:tt)* } $($handler:tt)*) => { attempt!{@recurse ($e) { $($tail)* } $($handler)* } }; } attempt!{{ do_step1(); do_step2(); do_step3(); } catch (e) { println!("Failed to perform necessary steps: {}", e); }}
ou si vous voulez une syntaxe plus compacte, vous pouvez le faire avec une macro:
if let Err(e) = do_step_1().and_then(do_step_2).and_then(do_step_3) { println!("Failed to perform necessary steps"); }
Il existe également une fonctionnalité instable appelée try_blocks
( https://doc.rust-lang.org/beta/unstable-book/language-features/try-blocks.html , https://github.com/rust-lang/rust/ numéros / 31436 )
Exemple d'utilisation:
#![feature(try_blocks)] fn main() { // you need to define the result type explicitly let result: Result<(), Error> = try { do_step_1()?; do_step_2()?; do_step_3()?; }; if let Err(e) = result { println!("Failed to perform necessary steps, ({:?})", e); } } fn do_step_1() -> Result<(), Error> { Ok(()) } fn do_step_2() -> Result<(), Error> { Ok(()) } fn do_step_3() -> Result<(), Error> { Err(Error::SomeError) } #[derive(Debug)] enum Error { SomeError, }