我有一个函数返回一个Result:
fn find(id: &Id) -> Result<Item, ItemError> {
// ...
}
Run Code Online (Sandbox Code Playgroud)
然后另一个使用它像这样:
let parent_items: Vec<Item> = parent_ids.iter()
.map(|id| find(id).unwrap())
.collect();
Run Code Online (Sandbox Code Playgroud)
如何在任何map迭代中处理失败的情况?
我知道我可以使用flat_map,在这种情况下,错误结果将被忽略:
let parent_items: Vec<Item> = parent_ids.iter()
.flat_map(|id| find(id).into_iter())
.collect();
Run Code Online (Sandbox Code Playgroud)
Result迭代器有0或1个项目,具体取决于成功状态,flat_map如果为0则会过滤掉它.
但是,我不想忽略错误,我想改为使整个代码块停止并返回一个新错误(基于映射中出现的错误,或者只是转发现有错误).
如何在Rust中最好地处理这个问题?
在Rust中,我认为处理可恢复错误的惯用方法是使用Result.例如,这个功能显然是惯用的:
fn do_work() -> Result<u64, WorkError> {...}
Run Code Online (Sandbox Code Playgroud)
当然,还有一些具有单一,明显的故障状态的功能,因此使用Option类型.一个惯用的例子是这样的:
fn do_work() -> Option<u64>
Run Code Online (Sandbox Code Playgroud)
这一切都在文档中直接解决.但是,我对函数可能失败的情况感到困惑,但在成功时没有任何有意义的值.比较以下两个功能:
fn do_work() -> Option<WorkError>
// vs
fn do_work() -> Result<(), WorkError>
Run Code Online (Sandbox Code Playgroud)
我只是不确定哪一个更惯用,或者更常用于现实世界的Rust代码.我这样的问题的首选资源是Rust书,但我不认为这是在" 错误处理 "部分中解决的.我也没有任何其他Rust文档的运气.
当然,这似乎是相当主观的,但我正在寻找权威的来源,要么说明哪种形式是惯用的,要么说明为什么一种形式优于(或劣等)另一种形式.(我也很好奇这个约定如何与其他大量使用"错误作为值"的语言相比,比如Go和Haskell.)
我有这样的代码:
let things = vec![/* ...*/]; // e.g. Vec<String>
things
.map(|thing| {
let a = try!(do_stuff(thing));
Ok(other_stuff(a))
})
.filter(|thing_result| match *thing_result {
Err(e) => true,
Ok(a) => check(a),
})
.map(|thing_result| {
let a = try!(thing_result);
// do stuff
b
})
.collect::<Result<Vec<_>, _>>()
Run Code Online (Sandbox Code Playgroud)
在语义方面,我想在第一个错误后停止处理.
上面的代码有效,但感觉非常麻烦.有没有更好的办法?我查看了类似的文档filter_if_ok,但我没有找到任何东西.
我知道collect::<Result<Vec<_>, _>>,它很有效.我特意试图消除以下样板:
match的thing_result.我觉得这应该只是一个单行,例如.filter_if_ok(|thing| check(a)).map,我都要包含一个额外的声明let a = try!(thing_result);,以便处理一个可能性Err.再一次,我觉得这可以被抽象出来.map_if_ok(|thing| ...).有没有其他方法可以用来获得这种简洁程度,或者我只是需要强硬一点?
我首先想到的是map对Option的,但我不能用try!从封闭的内部.该match声明看起来是不必要的,但我无法弄清楚如何简化它.
fn example<T, E>(val: Option<Result<T, E>>) -> Result<Option<T>, E> {
Ok(match val {
Some(v) => Some(v?),
None => None
})
}
Run Code Online (Sandbox Code Playgroud) async fn handle_rejection(err: Rejection) -> Result<impl Reply, Infallible> {
Run Code Online (Sandbox Code Playgroud)
Result<ok, err>但是,这样的错误是绝对错误且永远无法达到的,有什么好处呢?为什么不直接返回一个impl Reply?
我在 PostgreSQL 中使用 Diesel ORM 包装器。我正在关注他们网站上的指南,其中包含以下代码:
pub fn establish_connection() -> PgConnection {
dotenv().ok();
let database_url = env::var("DATABASE_URL")
.expect("DATABASE_URL must be set");
PgConnection::establish(&database_url)
.expect(&format!("Error connecting to {}", database_url))
}
Run Code Online (Sandbox Code Playgroud)
我dotenv()通过 dotenv 文档了解了它的作用 - 它加载了 env 文件。在源代码中,我看到它dotenv()返回一个Result. 那ok()做什么呢?它是否解开结果?如果是这样,为什么不使用unwrap()?
我有一些函数会在失败时返回不同的错误类型。
首先,我有一个构建器,其中包含此方法:
#[derive(Debug)]
pub enum BuilderError {
ElementMissing(&'static str),
}
pub fn spawn(self) -> Result<ServiceStatus, BuilderError>
Run Code Online (Sandbox Code Playgroud)
所以它会BuildError在失败时返回一个。
现在,我有另一个函数会返回另一个错误:
#[derive(Debug)]
pub enum XmlError {
XmlCreationFailed(writer::Error),
ConversionToUtf8(FromUtf8Error),
}
pub fn create_xml(service_status: super::ServiceStatus) -> Result<String, XmlError>
Run Code Online (Sandbox Code Playgroud)
这个想法是我使用构建器创建一个ServiceStatus对象并使用它来创建一个带有create_xml函数的 XML 字符串。
为此,我有以下代码:
#[derive(Debug)]
pub enum WebserviceError {
XmlError(XmlError),
BuilderError(BuilderError),
}
impl std::error::Error for WebserviceError {
...
}
impl From<XmlError> for WebserviceError {
fn from(error: XmlError) -> WebserviceError {
WebserviceError::XmlError(error)
}
}
impl From<BuilderError> for WebserviceError {
fn from(error: BuilderError) …Run Code Online (Sandbox Code Playgroud) 以下是我可以使用Rust 1.23.0编译的有效文件:
fn main() {
let r = String::from("a");
let a = Some(&r);
let b = match a {
Some(name) => name,
None => "",
};
println!("{}", b);
}
Run Code Online (Sandbox Code Playgroud)
虽然下面的代码
fn main() {
let r = String::from("a");
let a = Some(&r);
let b = a.unwrap_or("");
println!("{}", b);
}
Run Code Online (Sandbox Code Playgroud)
错误失败:
fn main() {
let r = String::from("a");
let a = Some(&r);
let b = match a {
Some(name) => name,
None => "",
};
println!("{}", b);
}
Run Code Online (Sandbox Code Playgroud)
据我所知,编译器在此处确定类型时的推理如下:
在使用a的情况下,match确定 …
我正在尝试泛化函数Result返回的a reqwest::blocking::get。它返回 aResult<reqwest::blocking::Response, reqwest::Error>但调用它的函数返回 a Result<reqwest::blocking::Response, Box<dyn std::error::Error>。
这是第一次尝试:
fn get_example_fails() -> Result<Response, Box<dyn Error>> {
let result = blocking::get("http://example.com");
result.map_err(|error| Box::new(error))
}
Run Code Online (Sandbox Code Playgroud)
它有以下错误,我不知道如何修复,但觉得通过一些小的调整可能会更惯用 - 但我不确定要调整什么:
error[E0308]: mismatched types
--> src/bittrex.rs:143:9
|
141 | fn get_example_fails() -> Result<Response, Box<dyn Error>> {
| -------------------------------- expected `Result<reqwes
t::blocking::Response, Box<(dyn StdError + 'static)>>` because of return type
142 | let result = blocking::get("http://example.com");
143 | result.map_err(|error| Box::new(error))
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected trait object `dyn StdError`,
found …Run Code Online (Sandbox Code Playgroud) 我无法从 a 返回函数的结果Result。每个教程只展示如何使用 Result,而不展示如何从中返回值。
fn main(){
let mut a: Vec<String> = Vec::new();
a = gottem();
println!("{}", a.len().to_string());
//a.push(x.to_string()
}
async fn gottem() -> Result<Vec<String>, reqwest::Error> {
let mut a: Vec<String> = Vec::new();
let res = reqwest::get("https://www.rust-lang.org/en-US/")
.await?
.text()
.await?;
Document::from(res.as_str())
.find(Name("a"))
.filter_map(|n| n.attr("href"))
.for_each(|x| println!("{}", x));
Ok(a)
}
Run Code Online (Sandbox Code Playgroud)
我收到以下错误:
fn main(){
let mut a: Vec<String> = Vec::new();
a = gottem();
println!("{}", a.len().to_string());
//a.push(x.to_string()
}
async fn gottem() -> Result<Vec<String>, reqwest::Error> {
let mut a: Vec<String> = Vec::new();
let …Run Code Online (Sandbox Code Playgroud) rust ×10
rust-result ×10
optional ×2
reqwest ×2
generics ×1
idiomatic ×1
iterator ×1
map-function ×1
option ×1
warp ×1