You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为什么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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.23 15:18:07