问题 在另一个线程中从“恐慌!”中恢复


我知道在Rust中没有try / catch,你不能从当前恐慌的线程中抛出滚动保存。

我认识你 不应该 创建和处理这样的错误。这只是为了举个例子。

但是,我想知道从恐慌中恢复的最佳方法是什么。这就是我现在拥有的:

use std::thread;

fn main() {
    println!("Hello, world!");

    let h = thread::spawn(|| {
        thread::sleep_ms(1000);
        panic!("boom");
    });

    let r = h.join();
    match r {
        Ok(r) => println!("All is well! {:?}", r),
        Err(e) => println!("Got an error! {:?}", e)
    }

    println!("Exiting main!");
}

有没有更好的方法来处理来自其他线程的错误?有没有办法捕捉恐慌的信息?这似乎只告诉我错误是类型的 Any。谢谢!


1160
2018-06-13 22:40


起源



答案:


暂且不说“你应该使用 Result 在可能的情况下,“是的,这基本上就是你如何在Rust中引起恐慌。请记住,”恢复“可能不是在Rust中表达这种情况的最佳方式。你真的没有从Rust的恐慌中恢复过来,你 隔离 然后他们 检测 他们。没有 On Error Resume Next :P。

也就是说,有两件事要添加到您的示例中。首先是如何得到恐慌信息。关键的观察是 Any,为了使用,必须 明确地 向下倾斜到它包含的确切的具体类型。在这种情况下,由于恐慌消息是a &'static str,你需要向下倾斜。

第二件事是夜间有一个新的API叫做 catch_panic 这可以让你孤立恐慌  必须开始一个线程。也就是说,它产生了与产生新线程相同的限制:你不能传递非线程'static 隔离边界的参考。请注意,这是一个 不稳定 加成;还没有关于稳定性的保证,你需要一个夜间编译器来访问它。

这是一个显示这两者的例子。你也可以 在Rust Playpen上运行

#![feature(catch_panic)]

use std::thread;

fn main() {
    println!("Hello, world!");

    let h = thread::spawn(|| {
        thread::sleep_ms(500);
        panic!("boom");
    });

    let r = h.join();
    handle(r);

    let r = thread::catch_panic(|| {
        thread::sleep_ms(500);
        panic!(String::from("boom again!"));
    });

    handle(r);

    println!("Exiting main!");
}

fn handle(r: thread::Result<()>) {
    match r {
        Ok(r) => println!("All is well! {:?}", r),
        Err(e) => {
            if let Some(e) = e.downcast_ref::<&'static str>() {
                println!("Got an error: {}", e);
            } else {
                println!("Got an unknown error: {:?}", e);
            }
        }
    }
}

9
2018-06-14 00:11



完善!关于错误格式的一点 &'static str 正是我需要的。谢谢!我有点惊讶的是,现在Rust已经达到了1.0,但是更多的东西不稳定,但也很高兴让他们在他们准备好之前不要在野外。 - jocull
@jocull“1.0”并不意味着“我们已经完成了”,它只是意味着“好吧,我们现在每隔几天就会停止破坏一切。”如果你希望标准库是“功能完整”,因为Rust是1.0,你将会非常痛苦地失望。 :) - DK.
@DK。:我宁愿说“如果你希望Rust现在停止发展,那它就是1.0,那你就会惊喜不已”:) - Matthieu M.
请注意,您可能还想检查 e.downcast_ref::<String>() 如果恐慌也可以是非静态错误消息。 - robinst


答案:


暂且不说“你应该使用 Result 在可能的情况下,“是的,这基本上就是你如何在Rust中引起恐慌。请记住,”恢复“可能不是在Rust中表达这种情况的最佳方式。你真的没有从Rust的恐慌中恢复过来,你 隔离 然后他们 检测 他们。没有 On Error Resume Next :P。

也就是说,有两件事要添加到您的示例中。首先是如何得到恐慌信息。关键的观察是 Any,为了使用,必须 明确地 向下倾斜到它包含的确切的具体类型。在这种情况下,由于恐慌消息是a &'static str,你需要向下倾斜。

第二件事是夜间有一个新的API叫做 catch_panic 这可以让你孤立恐慌  必须开始一个线程。也就是说,它产生了与产生新线程相同的限制:你不能传递非线程'static 隔离边界的参考。请注意,这是一个 不稳定 加成;还没有关于稳定性的保证,你需要一个夜间编译器来访问它。

这是一个显示这两者的例子。你也可以 在Rust Playpen上运行

#![feature(catch_panic)]

use std::thread;

fn main() {
    println!("Hello, world!");

    let h = thread::spawn(|| {
        thread::sleep_ms(500);
        panic!("boom");
    });

    let r = h.join();
    handle(r);

    let r = thread::catch_panic(|| {
        thread::sleep_ms(500);
        panic!(String::from("boom again!"));
    });

    handle(r);

    println!("Exiting main!");
}

fn handle(r: thread::Result<()>) {
    match r {
        Ok(r) => println!("All is well! {:?}", r),
        Err(e) => {
            if let Some(e) = e.downcast_ref::<&'static str>() {
                println!("Got an error: {}", e);
            } else {
                println!("Got an unknown error: {:?}", e);
            }
        }
    }
}

9
2018-06-14 00:11



完善!关于错误格式的一点 &'static str 正是我需要的。谢谢!我有点惊讶的是,现在Rust已经达到了1.0,但是更多的东西不稳定,但也很高兴让他们在他们准备好之前不要在野外。 - jocull
@jocull“1.0”并不意味着“我们已经完成了”,它只是意味着“好吧,我们现在每隔几天就会停止破坏一切。”如果你希望标准库是“功能完整”,因为Rust是1.0,你将会非常痛苦地失望。 :) - DK.
@DK。:我宁愿说“如果你希望Rust现在停止发展,那它就是1.0,那你就会惊喜不已”:) - Matthieu M.
请注意,您可能还想检查 e.downcast_ref::<String>() 如果恐慌也可以是非静态错误消息。 - robinst