Vla*_*eev 0 parsing parser-combinators rust nom
假设我想创建一个多次使用另一个解析器的组合器,例如,解析由两种引号分隔的字符串:
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,
)
}
Run Code Online (Sandbox Code Playgroud)
正如预期的那样,该解析器无法编译并出现“使用移动值”错误:
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,
)
}
Run Code Online (Sandbox Code Playgroud)
但是,我不能只将Copyor添加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)
}
}
Run Code Online (Sandbox Code Playgroud)
现在,由于move关键字的存在,该f值被移至闭包中。然后,在返回的闭包内,我直接调用复杂解析器组合器,并且除了输出/错误之外,闭包不会返回任何内容,这意味着我可以自由地使用对f.
| 归档时间: |
|
| 查看次数: |
1116 次 |
| 最近记录: |