Rust:如何覆盖默认的报错方式?
Rust: how to override the default way of reporting error?
当 Rust 中发生错误时,大多数 Rust 标准和第三方库(例如无论如何)只会将错误消息打印到 stdout/stderr。我需要的是用我自己的函数覆盖它。例如,用位置信息调用Windows API MessageBox(哪个文件和行会崩溃)。
到目前为止,我尝试了几种方法,每一种都缺少一些东西。
- 写下我的自定义错误,并覆盖它的
Debug
特性。问题是这个错误类型需要能够包装任何潜在的错误(例如 dyn std::error::Error
),这样我仍然可以写
fn test() -> std::result::Result<(), CustomError> {
...
if (has_windows_error) {
return Err(WindowsError(123))?;
}
if (has_io_error) {
return Err(IoError(123))?;
}
Ok(())
}
然而,这意味着 CustomError 需要同时实现 std::error::Error
和 From<std::error::Error>
,这两者相互冲突。
编写我的自定义结果类型,并实现Try
。这种方法需要接触实验 #![feature(try_trait_v2)]
.
使用std::panic::set_panic_hook()
,然后永远不要在代码中使用?
。相反,仅立即 unwrap()
所有 Result
。这是必需的,因为如果我允许错误出现,我将丢失 PanicInfo
.
中的位置信息
我对 Rust 比较陌生,所以我可能遗漏了很多东西。选项 3 是我目前正在使用的,尽管我不喜欢它如何迫使我放弃惯用的编码风格。
目前实现自定义错误输出的最简洁、侵入性较小的方法是什么?
选项 3 肯定不是这里的方法。在 Rust 中,panic 意味着不可恢复的错误,根据我过去 2 年在社区中的经验,这条准则得到了相当认真的对待。此外,选项 1 和 2 添加了相当大的 side-effects 操作,而这些操作从来都不是为了隐藏这样的东西。
此外,我不确定您所说的“第 3 方库(例如,无论如何)只会将错误消息打印到 stdout/stderr”是什么意思。如果你的函数 returns 一个 anyhow::Result<T>
并且发生错误,那么发生的只是错误被转换为 anyhow::Error
,除非你打印它,否则它不会被打印出来。
底线是 Rust 中没有“错误处理框架”。 Results
一点也不特别,事实上我鼓励你阅读 the source code. If you want to handle a result in a certain way, then match on it and write the code to handle it. Moreover the panic handling machinery is not meant to elevate them to something like C++ exceptions. You can read more about the motivations for it here。
听起来最适合你的方法是使用 anyhow
或类似的东西,在你的程序中的某些时候你可以匹配结果,转换 anyhow::Error
(或 std::error::Error
你选择的实现者)到一个字符串并打开一个消息框。如果您想包含有关错误发生位置的文件和行信息,则可以通过标准库提供的 file!
and line!
宏将其添加到错误的 message/data 中。这可能类似于以下内容:
pub fn main() {
if let Err(error) = try_main() {
// show_message_box implementation not shown
show_message_box(error.to_string());
}
}
pub fn try_main() -> anyhow::Result<()> {
// code which makes extensive use of `?`
}
请注意,Rust 的错误处理方法与许多其他广泛使用的语言不同,因此需要改变编码风格。错误是故意侵入你的代码,所以你实际上正确地处理了它们,这是我随着时间的推移而非常感激的事情。事实上,Rust 的特质使它成为一种非常固执己见的语言,所以当你遇到痛点时,我建议不要尝试使用超出预期用途的语言特性来解决它们,因为这比解决你的问题更有可能导致额外的痛点。
当 Rust 中发生错误时,大多数 Rust 标准和第三方库(例如无论如何)只会将错误消息打印到 stdout/stderr。我需要的是用我自己的函数覆盖它。例如,用位置信息调用Windows API MessageBox(哪个文件和行会崩溃)。
到目前为止,我尝试了几种方法,每一种都缺少一些东西。
- 写下我的自定义错误,并覆盖它的
Debug
特性。问题是这个错误类型需要能够包装任何潜在的错误(例如dyn std::error::Error
),这样我仍然可以写
fn test() -> std::result::Result<(), CustomError> {
...
if (has_windows_error) {
return Err(WindowsError(123))?;
}
if (has_io_error) {
return Err(IoError(123))?;
}
Ok(())
}
然而,这意味着 CustomError 需要同时实现 std::error::Error
和 From<std::error::Error>
,这两者相互冲突。
编写我的自定义结果类型,并实现
Try
。这种方法需要接触实验#![feature(try_trait_v2)]
.使用
中的位置信息std::panic::set_panic_hook()
,然后永远不要在代码中使用?
。相反,仅立即unwrap()
所有Result
。这是必需的,因为如果我允许错误出现,我将丢失PanicInfo
.
我对 Rust 比较陌生,所以我可能遗漏了很多东西。选项 3 是我目前正在使用的,尽管我不喜欢它如何迫使我放弃惯用的编码风格。
目前实现自定义错误输出的最简洁、侵入性较小的方法是什么?
选项 3 肯定不是这里的方法。在 Rust 中,panic 意味着不可恢复的错误,根据我过去 2 年在社区中的经验,这条准则得到了相当认真的对待。此外,选项 1 和 2 添加了相当大的 side-effects 操作,而这些操作从来都不是为了隐藏这样的东西。
此外,我不确定您所说的“第 3 方库(例如,无论如何)只会将错误消息打印到 stdout/stderr”是什么意思。如果你的函数 returns 一个 anyhow::Result<T>
并且发生错误,那么发生的只是错误被转换为 anyhow::Error
,除非你打印它,否则它不会被打印出来。
底线是 Rust 中没有“错误处理框架”。 Results
一点也不特别,事实上我鼓励你阅读 the source code. If you want to handle a result in a certain way, then match on it and write the code to handle it. Moreover the panic handling machinery is not meant to elevate them to something like C++ exceptions. You can read more about the motivations for it here。
听起来最适合你的方法是使用 anyhow
或类似的东西,在你的程序中的某些时候你可以匹配结果,转换 anyhow::Error
(或 std::error::Error
你选择的实现者)到一个字符串并打开一个消息框。如果您想包含有关错误发生位置的文件和行信息,则可以通过标准库提供的 file!
and line!
宏将其添加到错误的 message/data 中。这可能类似于以下内容:
pub fn main() {
if let Err(error) = try_main() {
// show_message_box implementation not shown
show_message_box(error.to_string());
}
}
pub fn try_main() -> anyhow::Result<()> {
// code which makes extensive use of `?`
}
请注意,Rust 的错误处理方法与许多其他广泛使用的语言不同,因此需要改变编码风格。错误是故意侵入你的代码,所以你实际上正确地处理了它们,这是我随着时间的推移而非常感激的事情。事实上,Rust 的特质使它成为一种非常固执己见的语言,所以当你遇到痛点时,我建议不要尝试使用超出预期用途的语言特性来解决它们,因为这比解决你的问题更有可能导致额外的痛点。