21
votes

Quel est l'équivalent de Rust d'une instruction try-catch?

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.


0 commentaires

3 Réponses :


21
votes

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");
    }
}

Terrain de jeux

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).


2 commentaires

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é .



16
votes

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");
}

terrain de jeux


0 commentaires

1
votes

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,
}


0 commentaires