我有以下代码:
fn main() {
let xs = vec!["1i32".to_string(), "2".to_string(), "3".to_string()];
let ys = do_some(xs);
println!("{:?}", ys);
}
fn do_some(tokens: Vec<String>) -> Result<Vec<String>, bool> {
tokens
.into_iter()
.map(|token: String| Ok(token))
.map(|token: Result<String, bool>| token.map(|s| s + "a"))
.fold(Ok(Vec::new()), |acc, s| acc.push(s))
}
在行.map(|token| Ok(token))
之后,我希望调用map
会在Result
而不是Iterator
上执行,因此可以解开Result
,但我得到Result<String, bool>
作为输出数据:
error[E0599]: no method named `push` found for type `std::result::Result<std::vec::Vec<std::string::String>, bool>` in the current scope
--> src/main.rs:12:44
|
12 | .fold(Ok(Vec::new()), |acc, s| acc.push(s))
| ^^^^
在Rust中编写类似函数的代码的最佳方法是什么?
我知道and_then
,但似乎无法在此链中使用。
答案 0 :(得分:1)
我真的不能说出确切的意思,但是-根据do_some
的签名来看-我假设您有一个Vec<String>
,一个在String
上运行的函数,返回Result<String, bool>
,并且您想将此功能应用于Vec
中的每个元素,并且如果全部都是Vec
,则将它们放入Ok
中。如果遇到Err
,则想返回一个Err
。可以达到以下目的:
fn do_some(tokens: Vec<String>) -> Result<Vec<String>, bool> {
tokens
.into_iter()
.map(|token: String| Ok(token)) // or any other Fn(String)->Result<String, bool>
.map(|token: Result<String, bool>| token.map(|s| s + "a"))
.collect()
}
这使用collect
,依靠FromIter
和you can convert an iterator over Result
s into a Result
。
请注意,您可以使所有这些变得更通用:
Vec
,可以是Iterator
上的String
。String
转换为Result<String, bool>
或将某些Result<String, ErrorType>
转换为ErrorType
的转换函数进行参数化。 Vec
作为成功的返回类型,而是任何实现FromIter
的东西(通常是容器类型)。执行此操作的第一步可能如下所示:
fn do_some<
ErrorType,
Tokens: std::iter::IntoIterator<Item=String>, // an iterable yielding String
StringToResult: Fn(String) -> Result<String, ErrorType>,
>(
tokens: Tokens,
string_to_result: StringToResult,
) -> Result<Vec<String>, ErrorType> {
tokens
.into_iter()
.map(|s| string_to_result(s).map(|s| s + "a"))
.collect()
}
可以如下使用:
fn main() {
println!("{:?}",
do_some(vec!["i1".to_string(), "i2".to_string(), "i3".to_string()], |s| {
if s.starts_with("i") {
Ok(s)
} else {
Err(s + " i does not start with i")
}
})
);
println!("{:?}",
do_some(vec!["i1".to_string(), "i2".to_string(), "A3".to_string()], |s| {
if s.starts_with("i") {
Ok(s)
} else {
Err(s + " i does not start with i")
}
})
);
}
答案 1 :(得分:0)
您可以将结果收集在中间容器中,然后从那里处理所有错误(请注意,您将需要更改函数的返回值):
fn internal_eval(&mut self, tokens: Vec<String>) -> Result<(), Error> {
tokens
// Use `into_iter` to iterate over owned objects
.into_iter()
.map(|token| parse_token(token))
.collect::<Result<Vec<_>, _>>()?
.into_iter()
.map(|token1| do_something_with_token1(token1))
.fold(some_init, |acc, x| {
// reduce
});
// ...
}
如果您无力创建一个中间容器,也可以这样做(可读性稍差):
fn internal_eval(&mut self, tokens: Vec<String>) -> Result<(), Error> {
tokens
.into_iter()
.map(|token| parse_token(token))
.map(|token1_res| token1_res.map(|token1| do_something_with_token1(token1) ))
.try_fold(some_init, |acc, x| -> Result<SomeType, Error> {
let val = x??;
// ...
});
Ok(())
}
更新
fn do_some(tokens: Vec<String>) -> Result<Vec<String>, bool> {
Ok(tokens
.into_iter()
.map(|token: String| Ok(token))
.map(|token: Result<String, bool>| token.map(|s| s + "a"))
.try_fold(Vec::new(), |mut acc, s| { acc.push(s?); Ok(acc) })?)
}