如何在nom的alt组合子中复用无法移动的小型解析器?
解决nom中复用闭包子解析器的移动问题
问题根源
你遇到的问题是:nom组合出来的闭包型解析器默认仅实现FnMut trait,没有实现Clone或Copy,第一次使用时所有权会被移动,后续无法重复调用。
简洁解决方案
方案1:将子解析器定义为独立函数
函数可以被多次调用,每次都会生成新的解析器实例,完全避免所有权移动问题,这也是最常用的解决方案:
use nom::{ character::complete::{alphanumeric1, tag}, combinator::{map, recognize}, multi::many0, sequence::separated_pair, branch::alt, IResult, }; // 把word解析器定义为函数 fn word(i: &str) -> IResult<&str, &str> { recognize(many0(alt((alphanumeric1, tag("_")))))(i) } fn parse_dot_sep_words_or_word(i: &str) -> IResult<&str, (&str, &str)> { let dot_sep_word = separated_pair(word, tag("."), word); alt(( map(word, |single_word| ("", single_word)), map(dot_sep_word, |(a,b)| (a,b)) ))(i) }
方案2:用BoxedParser装箱实现复用
如果不想单独定义函数,可以将解析器装箱为BoxedParser,它实现了Clone trait,允许我们复制解析器实例:
use nom::{ character::complete::{alphanumeric1, tag}, combinator::{map, recognize}, multi::many0, sequence::separated_pair, branch::alt, IResult, error::ErrorKind, Parser, }; fn parse_dot_sep_words_or_word(i: &str) -> IResult<&str, (&str, &str)> { let word = recognize(many0(alt((alphanumeric1, tag("_"))))) .boxed::<_, (&str, ErrorKind)>(); let dot_sep_word = separated_pair(word.clone(), tag("."), word.clone()); alt(( map(word, |single_word| ("", single_word)), map(dot_sep_word, |(a,b)| (a,b)) ))(i) }
方案3:使用nom的parser!宏
nom提供的parser!宏可以帮我们快速生成可复用的解析器,本质是自动生成函数:
use nom::{ character::complete::{alphanumeric1, tag}, combinator::{map, recognize}, multi::many0, sequence::separated_pair, branch::alt, IResult, parser, }; // 用parser!宏定义可复用的word解析器 parser!(fn word(i: &str) -> IResult<&str, &str> { recognize(many0(alt((alphanumeric1, tag("_"))))) }); fn parse_dot_sep_words_or_word(i: &str) -> IResult<&str, (&str, &str)> { let dot_sep_word = separated_pair(word, tag("."), word); alt(( map(word, |single_word| ("", single_word)), map(dot_sep_word, |(a,b)| (a,b)) ))(i) }
内容的提问来源于stack exchange,提问作者exocortex
相关产品推荐
相关产品推荐

