假设我想创建一个组合器,它多次使用另一个解析器,例如,解析由两种引号分隔的字符串:
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
orClone
到F
边界:很多解析器,特别是由 Nom 的内置函数返回的解析器,既不实现Clone
也不实现Copy
。我也不能&f
用作 的参数tuple
,因为那将是一个借用检查错误(f
是一个临时的本地值,因此不可能返回用它构造的解析器)。
我看到这样做的唯一方法实际上是alt
直接在函数中重新实现逻辑,通过在一系列嵌套match
语句中展开它,但这似乎真的不是最理想的。或者也许我错过了一些简单的东西,实际上可以只使用组合器来做我想做的事情?
我很确定有更好的方法来专门编写quoted
如上所述的组合器,如果有人展示它会很好,但我的问题更笼统 - 我如何编写重用相同解析器的组合器?