为什么tuple()中不能两次使用同一个nom解析器?如何复用本地定义的解析器
问题原因
你定义的num是一个实现了FnMut trait的解析器实例,Rust所有权规则要求非Copy类型的变量值只能被消费一次:第一次把num传入tuple时就已经转移了它的所有权,第二次再使用num自然会触发所有权报错。
解决方案
方案1:封装解析器为独立函数
直接把数字解析逻辑封装为独立的解析器函数,每次调用都会生成新的解析器实例,不存在所有权冲突:
use nom::character::complete::digit1; use nom::combinator::map_res; use nom::error::Error; use nom::sequence::tuple; use nom::Err; use nom::IResult; type E<'a> = Err<Error<&'a str>>; // 封装为独立的解析器函数 fn num(input: &str) -> IResult<&str, i32> { map_res(digit1, |s: &str| s.parse::<i32>())(input) } fn parse_double_int(input: &str) -> Option<(i32, i32)> { let mut pair = tuple((num, num)); let res: Result<_, E> = pair(&input.trim()); match res { Ok((_, (a, b))) => Some((a, b)), Err(_) => None, } }
方案2:克隆解析器实例
你当前定义的num解析器没有捕获外部变量,本身支持Clone,直接克隆一份给第二个参数即可:
fn parse_double_int(input: &str) -> Option<(i32, i32)> { let num = map_res(digit1, |s: &str| s.parse::<i32>()); // 克隆解析器实例避免所有权转移问题 let mut pair = tuple((num.clone(), num)); let res: Result<_, E> = pair(&input.trim()); match res { Ok((_, (a, b))) => Some((a, b)), Err(_) => None, } }
方案3:使用nom内置重复组合子
针对重复执行同一个解析器的场景,nom提供了count组合子专门处理这类需求,写法更简洁:
use nom::combinator::count; fn parse_double_int(input: &str) -> Option<(i32, i32)> { let num = map_res(digit1, |s: &str| s.parse::<i32>()); // 执行2次num解析器,返回长度为2的Vec let mut pair = count(num, 2); let res: Result<_, E> = pair(&input.trim()); match res { Ok((_, nums)) => Some((nums[0], nums[1])), Err(_) => None, } }
内容的提问来源于stack exchange,提问作者insitu
相关产品推荐
相关产品推荐

