我正在使用正则表达式包找到这个正则表达式的一些文本:
lazy_static! {
static ref FIND_STEPS_RE: Regex =
Regex::new(r"my regex").unwrap();
}
我想找到所有可能的捕获并迭代它们:
FIND_STEPS_RE.captures_iter(script_slice)
每个捕获的元素由2个值组成:操作和数字。例如,输出可以是:
[("+", "10"), ("-", "20"), ("*", "2")]
我想迭代它,解析数字并应用操作。
我试过了:
let e = FIND_STEPS_RE.captures_iter(script_slice)
.fold(0, |sum, value| apply_decoding_step)?;
其中apply_decoding_step
是:
fn apply_decoding_step(sum: i32, capture: regex::Captures<>) -> Result<i32> {
let number = parse_number(&capture[2])?;
match &capture[1] {
"+" => Ok(s + number),
"-" => Ok(s - number),
"*" => Ok(s * number),
"/" => Ok(s / number),
_ => bail!("Unknown step operator"),
}
}
但我收到了这个错误:
error[E0271]: type mismatch resolving `<fn(i32, regex::Captures<'_>) -> std::result::Result<i32, Error> {apply_decoding_step} as std::ops::FnOnce<(i32, regex::Captures<'_>)>>::Output == i32`
--> src/main.rs:122:10
|
122 | .fold(seed, apply_decoding_step);
| ^^^^ expected enum `std::result::Result`, found i32
|
= note: expected type `std::result::Result<i32, Error>`
found type `i32`
我认为这是因为我试图将Result
折叠成i32
,但因为我需要解析第二个捕获值并且还需要otherwise
个案例在我的match
中,我该如何解决?
答案 0 :(得分:5)
作为jupp0r states,初始值必须与闭包的返回值具有相同的类型。
我建议使用Result::and_then
在发生错误时不做任何操作:
let result = x.iter().fold(Ok(0), |acc, &i| {
acc.and_then(|acc| apply_decoding_step(acc, i))
});
达成:
fn main() {
let x = [("+", "10"), ("-", "20"), ("*", "2")];
let result = x.iter().fold(Ok(0), |acc, &i| {
acc.and_then(|acc| apply_decoding_step(acc, i))
});
println!("{:?}", result);
}
fn apply_decoding_step(sum: i32, capture: (&str, &str)) -> Result<i32, ()> {
let number: i32 = capture.1.parse().expect("nope");
match capture.0 {
"+" => Ok(sum + number),
"-" => Ok(sum - number),
"*" => Ok(sum * number),
"/" => Ok(sum / number),
_ => Err(()),
}
}
这是一个企业级解决方案。我认为这样做的主要好处是迭代将在遇到第一个Err
时立即结束,而不是在列表的其余部分中旋转。次要的好处包括能够为每个部分编写非常细粒度的测试(从字符串解析,算术运算,积累等):
fn main() {
let x = [("+", "10"), ("-", "20"), ("*", "2")];
let result: Result<Accumulator, ()> = x.iter()
.map(|&(op, val)| {
let op = op.parse::<Op>()?;
let val = val.parse::<i32>().map_err(|_| ())?;
Ok((op, val))
})
.collect();
println!("{:?}", result);
}
use std::str::FromStr;
use std::iter::FromIterator;
#[derive(Debug)]
enum Op {
Add,
Sub,
Mul,
Div,
}
impl Op {
fn apply(&self, a: i32, b: i32) -> i32 {
use Op::*;
match *self {
Add => a + b,
Sub => a - b,
Mul => a * b,
Div => a / b,
}
}
}
impl FromStr for Op {
type Err = ();
fn from_str(s: &str) -> Result<Self, ()> {
use Op::*;
match s {
"+" => Ok(Add),
"-" => Ok(Sub),
"*" => Ok(Mul),
"/" => Ok(Div),
_ => Err(()),
}
}
}
#[derive(Debug)]
struct Accumulator(i32);
impl<'a> FromIterator<(Op, i32)> for Accumulator {
fn from_iter<I>(iter: I) -> Self
where
I: IntoIterator<Item = (Op, i32)>,
{
Accumulator(
iter.into_iter()
.fold(0, |acc, (op, val)| op.apply(acc, val)),
)
}
}
答案 1 :(得分:2)
仔细查看fold
的类型签名:
fn fold<B, F>(self, init: B, f: F) -> B
where
F: FnMut(B, Self::Item) -> B,
{ ... }
init
必须与f
的返回值具有相同的类型。这也是编译器在错误消息中告诉您的内容。你可以做到
fn apply_decoding_step(sum: Result<i32>, capture: regex::Captures<>) -> Result<i32> {
match sum {
Err(_) => sum,
Ok(s) => {
let number = parse_number(&capture[2])?;
match &capture[1] {
"+" => Ok(s + number),
"-" => Ok(s - number),
"*" => Ok(s * number),
"/" => Ok(s / number),
_ => bail!("Unknown step operator"),
}
}
}
}
然后使用Ok
种子调用它:
.fold(Ok(seed), apply_decoding_step);
现在,如果发生任何故障,您的fold
会返回Err
。
答案 2 :(得分:0)
您可以通过这样的自定义Iterator
功能扩展fold_result
(使用Result
的完整路径,因为您似乎正在导入生成的Result
类型由error_chain
):
trait IterExtFoldResult: Iterator + Sized {
#[inline]
fn fold_result<B, F, E>(self, mut init: B, mut f: F) -> ::std::result::Result<B, E>
where
F: FnMut(B, Self::Item) -> ::std::result::Result<B, E>,
{
for i in self {
init = f(init, i)?;
}
Ok(init)
}
}
impl<I: Iterator> IterExtFoldResult for I {}
并像.fold_result(0, apply_decoding_step)
一样使用它。
这种方式fold
在f
返回错误时中止;如果你转发f
中的错误,编译器可能会或可能不会优化到早期返回。