Rust 正确的错误处理(使用问号自动从一种错误类型转换为另一种错误类型)
我想学习如何正确处理Rust中的错误。我已经读过和;现在我想知道如何处理此函数中的错误:Rust 正确的错误处理(使用问号自动从一种错误类型转换为另一种错误类型),rust,Rust,我想学习如何正确处理Rust中的错误。我已经读过和;现在我想知道如何处理此函数中的错误: fn get_synch_point(&self) -> Result<pv::synch::MeasPeriods, reqwest::Error> { let url = self.root.join("/term/pv/synch"); // self.root is url::Url let url = match url { Ok(url)
fn get_synch_point(&self) -> Result<pv::synch::MeasPeriods, reqwest::Error> {
let url = self.root.join("/term/pv/synch"); // self.root is url::Url
let url = match url {
Ok(url) => url,
// ** this err here is url::ParseError and can be converted to Error::Kind https://docs.rs/reqwest/0.8.3/src/reqwest/error.rs.html#54-57 **//
Err(err) => {
return Err(Error {
kind: ::std::convert::From::from(err),
url: url.ok(),
})
}
};
Ok(reqwest::get(url)?.json()?) //this return reqwest::Error or convert to pv::sych::MeasPeriods automaticly
}
处理该案件的适当模式是什么?对我来说,在这种情况下,reqwest::Error
是一个很好的解决方案,因此我希望避免定义自己的错误类型:
enum MyError {
Request(reqwest::Error),
Url(url::ParseError) // this already a part of request::Error::Kind!!!
}
不幸的是,在您的情况下,如果
reqwest
库没有提供这样做的方法(很可能没有),您就无法从其他错误类型创建reqwest::Error
。要解决这个非常常见的问题,特别是在使用多个库的应用程序中,正确的解决方案应该是以下之一:
实现将和转换为
故障
板条箱旨在定义Rust社区中推广的错误。它不仅提供了一个常见的错误类型和特征(它修复了std::error::error
trait的各种问题;请参见示例),还提供了定义自己的错误类型(例如,使用)的工具,以及跟踪错误上下文、原因和生成回溯的工具。此外,它试图与现有的错误处理方法尽可能兼容,因此可以使用它与使用其他较旧方法的库集成(std::error::error
,错误链
,快速错误
)。所以我强烈建议你在其他选项之前先考虑使用这个箱子。
我已经开始在我的应用程序项目中使用failure
,我无法表达错误处理变得多么容易和更好。我的做法如下:
结果
类型:
type Result<T> = std::result::Result<T, failure::Error>;
type Result=std::Result::Result;
Result
,使用问号运算符(?
)在错误和函数之间进行转换,例如或创建我自己的错误消息failure
编写一个库,但我认为对于库来说,创建声明为枚举的更具体的错误是很重要的,这可以通过failure\u-deriver
板条箱来完成。但是,对于应用程序来说,failure::Error
类型已经足够了。As,板条箱应该是您的起点。以下是我的解决方案:
use std::io;
use std::result;
use failure::{Backtrace, Fail};
/// This is a new error type manged by Oxide library.
/// The custom derive for Fail derives an impl of both Fail and Display.
#[derive(Debug, Fail)]
pub enum OxideError {
#[fail(display = "{}", message)]
GeneralError { message: String },
#[fail(display = "{}", message)]
IoError {
message: String,
backtrace: Backtrace,
#[cause]
cause: io::Error,
},
}
/// Create general error
pub fn general(fault: &str) -> OxideError {
OxideError::GeneralError {
message: String::from(fault),
}
}
/// Create I/O error with cause and backtrace
pub fn io(fault: &str, error: io::Error) -> OxideError {
OxideError::IoError {
message: String::from(fault),
backtrace: Backtrace::new(),
cause: error,
}
}
此错误枚举是可扩展的,允许它适应将来可能对程序进行的修改。在这种情况下,无法重用底层错误类型,因为无法构造其隐藏字段。即使在可能的情况下,我也会建议您不要这样做,以便使您的代码更灵活,更能经得起未来的考验 定义自定义错误类型可能需要编写大量样板文件,但幸运的是,有几个库可以减轻这种痛苦。上面已经提到了失败、错误链和快速错误,但我想向您指出我写的一个板条箱,其中包含的样板文件比其他板条箱更少:。有了它,你可以写:
#[macro_use] extern crate custom_error;
custom_error!{ MyError
Request{source: reqwest::Error} = "request error",
Url{source: url::ParseError} = "invalid url"
}
更新2020
rust编程语言正在快速发展,因此可以添加新的答案!我真的很喜欢,但现在我想我会是我的爱人
使用thisrerror::Error;
#[导出(错误,调试)]
发布枚举数据存储错误{
#[错误(“数据存储已断开”)]
断开连接(#[从]io::错误),
#[错误(“键`{0}`的数据不可用”)]
编校(字符串),
#[错误(“无效标头(应为{应为:?},已找到{已找到:?})”)]
无效标题{
应为:字符串,
找到:字符串,
},
#[错误(“未知数据存储错误”)]
不详,
}
这允许将io::Error
更改为DataStoreError::断开带有问号的?
。到这里来
有用链接:
其他有趣的板条箱:
- -基于std::Error::Error构建的灵活具体错误类型
- -情况正常:所有问题都已解决-SNAFU是一个库,可以在添加上下文时轻松地将底层错误分配到特定于域的错误中。(类似于此错误)
- -此板条箱包含一个宏,该宏可以更轻松地定义自定义错误,而无需编写大量样板代码
对于恐慌:
- -此板条箱旨在使proc宏中的错误报告简单易用
- -人类的恐慌信息。通过调用std::panic::set_hook来处理恐慌,从而使错误对人类有利
Oo。谢谢你的板条箱。我第一次使用failure,但现在我只想使用standard trait Error,这个宏非常简单!这是最多的投票,但失败和错误链增加了额外的复杂和非标准特征。如今,有些板条箱只能进行标准的防锈错误处理,例如:和。你能把它们也包括在这里吗?“失败”已经被弃用了无论如何,“更容易”和“thiserror”(更精确,就像图书馆一样)是现代的首选选择。两者都由同一作者编写,可以一起使用