折叠后返回结果的闭包

Sas*_*ssa 3 fold rust rust-result

我正在使用正则表达式包来找到这个正则表达式的一些文本:

lazy_static! {
    static ref FIND_STEPS_RE: Regex =
        Regex::new(r"my regex").unwrap();
}
Run Code Online (Sandbox Code Playgroud)

我想找到所有可能的捕获并迭代它们:

FIND_STEPS_RE.captures_iter(script_slice)
Run Code Online (Sandbox Code Playgroud)

每个捕获的元素由2个值组成:操作和数字.例如,输出可以是:

[("+", "10"), ("-", "20"), ("*", "2")]
Run Code Online (Sandbox Code Playgroud)

我想迭代它,解析数字并应用操作.

我试过了:

let e = FIND_STEPS_RE.captures_iter(script_slice)
    .fold(0, |sum, value| apply_decoding_step)?;
Run Code Online (Sandbox Code Playgroud)

在哪里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"),
    }
}
Run Code Online (Sandbox Code Playgroud)

但我得到了这个错误:

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`
Run Code Online (Sandbox Code Playgroud)

我认为这是因为我正在尝试将a折叠Result成a i32,但由于我需要解析第二个捕获值并且还需要otherwise我的情况,我match该如何解决?

She*_*ter 6

正如jupp0r所述,初始值必须与闭包的返回值具有相同的类型.

Iterator::fold发生错误时,我建议在折叠中不做任何操作:

let result = x.iter().try_fold(0, |acc, &i| apply_decoding_step(acc, i));
Run Code Online (Sandbox Code Playgroud)

完成:

fn main() {
    let x = [("+", "10"), ("-", "20"), ("*", "2")];

    let result = x.iter().try_fold(0, |acc, &i| 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(()),
    }
}
Run Code Online (Sandbox Code Playgroud)

这是一个企业级解决方案.我认为这样做的主要好处是迭代会在第一次Iterator::try_fold遇到迭代时结束,而不是在列表的其余部分旋转.次要的好处包括能够为每个部分编写非常细粒度的测试(从字符串解析,算术运算,累积等):

let result = x.iter().fold(Ok(0), |acc, &i| {
    acc.and_then(|acc| apply_decoding_step(acc, i))
});
Run Code Online (Sandbox Code Playgroud)


jup*_*p0r 3

仔细看看 的类型签名fold

fn fold<B, F>(self, init: B, f: F) -> B
 where
    F: FnMut(B, Self::Item) -> B,
{ ... }
Run Code Online (Sandbox Code Playgroud)

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"),
           }
       }
    }
}
Run Code Online (Sandbox Code Playgroud)

然后用Ok种子调用它:

.fold(Ok(seed), apply_decoding_step);
Run Code Online (Sandbox Code Playgroud)

现在,如果发生任何失败,您fold将返回一个Err.