问题
I have a function which performs string replacement in-place via regex::Regex::replace
via a closure which performs some operations on the Captures
:
pub fn solve_dice_expression(expression: String) -> Result<i64, Box<dyn Error>> {
lazy_static! {
static ref PATTERN: Regex = Regex::new(r"(\d+)d(\d+)").expect("Problem compiling regex");
}
// For every match on the Dice expression regex, roll it in-place.
let rolled_expression = PATTERN.replace(&expression, |caps: &Captures| {
let diceroll_str = &caps.get(0).unwrap().as_str().to_string();
let dice = Dice::from_string(&diceroll_str).unwrap();
return format!("{}", roll_dice(&mut rng, &dice));
});
// Calculate the result
let result = eval(&rolled_expression)?.as_int()?;
return Ok(result);
}
I try to have errors bubble up by returning Result<..., Box<dyn Error>>
, which mostly works via ?
. However, in the closure passed to regex::Regex::replace
, I am not sure how to propagate any possible errors that could happen since it expects a closure returning a String
and not a Result
.
What would be the correct way to handle errors happening in that closure?
回答1:
You cannot easily.
What you can do is smuggle out the error in a mutable Option
, then check that after the replacement is complete:
use regex::{Captures, Regex}; // 1.3.3
use std::borrow::Cow;
type Error = Box<dyn std::error::Error>;
type Result<T, E = Error> = std::result::Result<T, E>;
fn example<'s>(r: &Regex, s: &'s str) -> Result<Cow<'s, str>> {
let mut error = None;
let v = r.replace(s, |caps: &Captures| {
// TODO: Optimize by checking if we had an error already and exit early
let digits = caps.get(0).unwrap().as_str();
// Uncomment to see the failure
// let digits = "bad";
match digits.parse::<i32>() {
Ok(v) => Cow::Owned((v + 1).to_string()),
Err(e) => {
// Save the error somewhere
error = Some(e);
// We are going to discard the replacement,
// so it doesn't matter what we return
Cow::Borrowed("")
}
}
});
match error {
Some(e) => Err(Box::new(e)),
None => Ok(v),
}
}
fn main() {
let r = Regex::new(r"\d+").unwrap();
let v = example(&r, "1");
println!("{:?}", v);
}
You could also potentially implement the Replacer trait on your own type to streamline this and maybe slightly optimize it more.
来源:https://stackoverflow.com/questions/60068408/how-do-i-bubble-up-an-error-from-the-closure-passed-to-regexregexreplace