什么是Rust等同于try-catch语句?

Mar*_*lin 2 error-handling try-catch rust

是否可以一次处理多个不同的错误,而不必在Rust中单独处理而不使用其他功能?简而言之:Rust等价于try-catch语句?

早在2016年就提出了这样的功能(使用?and 进行一流的错误处理catch),但我不知道它产生了什么,以及2019年针对此类问题的解决方案的外观如何。

例如,执行以下操作:

try {
    do_step_1()?;
    do_step_2()?;
    do_step_3()?;
    // etc
} catch {
    alert_user("Failed to perform necessary steps");
}
Run Code Online (Sandbox Code Playgroud)

代替:

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(())
}
Run Code Online (Sandbox Code Playgroud)

我的程序有一个功能,可以检查注册表中各种不同位置的不同数据值,并返回一些汇总数据。它需要将许多try-cache语句与try-catch和其他try-catch一起使用。

Mik*_*nen 13

还有一个不稳定的功能,称为try_blockshttps://doc.rust-lang.org/beta/unstable-book/language-features/try-blocks.htmlhttps://github.com/rust-lang/rust/issues /31436 )

使用示例:

#![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,
}
Run Code Online (Sandbox Code Playgroud)


Web*_*rix 7

Rust中没有try catch语句。最接近的方法是?运算符。

但是,您不必创建函数和match语句来最终解决该问题。您可以在范围内定义闭包,并?在闭包内使用运算符。然后,将引发保留在闭包的返回值中,您可以在任意位置捕获它,如下所示:

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");
    }
}
Run Code Online (Sandbox Code Playgroud)

操场

是否可以一次处理多个不同的错误,而不必在Rust中单独处理而无需使用其他功能?

对的,这是可能的。Rust中有一个错误箱用于错误管理。使用Failure,您可以链接,转换,连接错误。将错误类型转换为一种常见类型后,您可以轻松地捕获(处理)它。

  • 请注意,您的闭包表达式正是 [`try` 块的用途](https://play.rust-lang.org/?version=nightly&amp;mode=debug&amp;edition=2018&amp;gist=805b37002e0965c5d0705b7ab11acbd)。 (4认同)
  • 只是插一句,但 `failure` 并不是唯一有助于错误管理的 crate。有很多,每个都有不同的侧重点。 (2认同)

Oli*_*nde 6

不确定它是否被认为是惯用的 Rust,但您可以使用匿名闭包来实现类似于以下的语法try/catch

fn do_step_1() -> Result<(), String> { Ok(()) }
fn do_step_2() -> Result<(), String> { Err("error at step 2".to_string()) }
fn do_step_3() -> Result<(), String> { Ok(()) }
fn alert_user(s: &str) { println!("{}", s); }

fn main() {
    (|| {
        do_step_1()?;
        do_step_2()?;
        do_step_3()?;
        Ok(())
    })().unwrap_or_else(|_err: String| {
        alert_user("Failed to perform the necessary steps");
    })
}
Run Code Online (Sandbox Code Playgroud)


Jmb*_*Jmb 5

ResultRust中的可以使用链接and_then。因此,您可以执行以下操作:

if let Err(e) = do_step_1().and_then(do_step_2).and_then(do_step_3) {
    println!("Failed to perform necessary steps");
}
Run Code Online (Sandbox Code Playgroud)

或者,如果您想要更紧凑的语法,则可以使用宏:

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);
}}
Run Code Online (Sandbox Code Playgroud)

操场