作为示例,我想解析一个字符串,该字符串可以是 2 个点分隔的单词,也可以是单个单词。每个“单词”都是字母数字和下划线字符的组合,因此我将单词解析器编写为闭包。在任何一种情况下,我都希望解析器函数返回一对单词,其中一个可能是空字符串。对于这个特定问题可能有更好的解决方案,但我只是想在这里激发我的问题。
用
nom
编写我的解析器,我偶然发现了以下问题:我无法将子解析器编写为闭包(以便重用它们),因为如果我在 alt
中多次使用它们,闭包就会被移动声明:
fn parse_dot_sep_words_or_word(i: &str) -> IResult<&str, (&str, &str)> {
let word = recognize(many0(alt((alphanumeric1, tag("_")))));
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)
}
这不起作用,因为一旦在
word
内部使用dot_sep_word
就会移动。遵循编译器的说明(“使用 &mut word”)也没有帮助。
我可以使用的唯一解决方案是每次使用
word
时写出 word
的定义。但这似乎与名义提供的优势违反直觉。
我在这里错过了什么?有没有简单的方法可以解决这个问题?
这有点令人惊讶,但是
recognize
不会返回最灵活的类型 impl Fn<..>
但您可以创建一个 Fn
闭包来执行相同的操作:
let word = |s| recognize(many0(alt((alphanumeric1, tag("_")))))(s);
因为它没有捕获闭包实现的任何环境
Copy
,所以你的其他代码无需任何更改即可工作。