假设我想创建一个组合器,该组合器多次使用另一个解析器,例如,解析由两种引号分隔的字符串:
fn quoted<'a, F: 'a, O, E: ParseError<&'a str>>(f: F) -> impl Fn(&'a str) -> IResult<&'a str, O, E>
where
F: Fn(&'a str) -> IResult<&'a str, O, E>,
{
map(
alt((
tuple((tag("'"), f, tag("'"))),
tuple((tag("\""), f, tag("\"")))
)),
|(_, res, _)| res,
)
}
正如预期的那样,此解析器无法编译为“使用移动值”错误:
149 | fn quoted<'a, F: 'a, O, E: ParseError<&'a str>>(f: F) -> impl Fn(&'a str) -> IResult<&'a str, O, E>
| - - move occurs because `f` has type `F`, which does not implement the `Copy` trait
| |
| consider adding a `Copy` constraint to this type argument
...
155 | tuple((tag("'"), f, tag("'"))),
| - value moved here
156 | tuple((tag("\""), f, tag("\"")))
| ^ value used here after move
但是,我不能仅将
Copy
或Clone
添加到F
边界:特别是Nom的内置函数返回的很多解析器,既没有实现Clone
也没有实现Copy
。我也不能将&f
用作tuple
的参数,因为这将是借入检查错误(f
是一个临时的本地值,因此无法返回使用它构造的解析器)。我看到的唯一方法实际上是直接在函数中重新实现
alt
逻辑,方法是按嵌套的match
语句序列展开它,但这似乎不是最佳选择。或者,也许我缺少一些简单的东西,而实际上有可能仅使用组合器来做我想做的事情?我敢肯定,如上所述,有一种更好的方式专门编写
quoted
组合器,如果有人显示它会很好,但是我的问题更笼统-我该如何编写使用相同解析器的组合器? 最佳答案
最简单的方法是对返回的闭包进行显式显示:
fn quoted<'a, F: 'a, O, E: ParseError<&'a str>>(f: F) -> impl Fn(&'a str) -> IResult<&'a str, O, E>
where
F: Fn(&'a str) -> IResult<&'a str, O, E>,
{
move |i| {
map(
alt((
tuple((tag("'"), &f, tag("'"))),
tuple((tag("\""), &f, tag("\"")))
)),
|(_, res, _)| res,
)(i)
}
}
现在,由于有了
move
关键字,f
值被移到了闭包中。然后,在返回的闭包内部,我直接调用复杂的解析器组合器,并且从闭包中返回除输出/错误之外的任何内容,这意味着我可以自由使用对f
的引用。关于parsing - Nom 5 : creating a combinator using another parser multiple times,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/56846090/