我正在尝试实现一些解析组合器。每个解析器组合器都是一个可变的闭包,但外部代码将每个组合器称为一个特征,该特征为调用组合器函数提供了一个全面的实现。
// Region of external code, CANNOT modify
type ParseResult<I, T> = Result<(I, T), String>;
trait Parser<T> {
fn parse<'a>(&mut self, input: &'a str) -> ParseResult<&'a str, T>;
}
// Blanket implementation for parser combinators
impl<F, T> Parser<T> for F
where F: FnMut(&str) -> ParseResult<&str, T> {
fn parse<'a>(&mut self, input: &'a str) -> ParseResult<&'a str, T> {
self(input)
}
}
// Example of an external combinator
fn external_combinator<P, T>(parser: P) -> impl FnMut(&str) -> ParseResult<&str, T>
where P: Parser<T> {
preceded_by(char_parser('a'), parser)
}
// My code begins here
fn char_parser(c: char) -> impl Fn(&str) -> ParseResult<&str, char> {
move |input: &str| {
let Some(rest) = input.strip_prefix(c) else {
return Err(format!("Input does not begin with {c}"));
};
Ok((rest, c))
}
}
fn delimited_by<Extracted>(
begin_char: char,
final_char: char,
mut parser: impl Parser<Extracted>
) -> impl FnMut(&str) -> ParseResult<&str, Extracted> {
move |input: &str| {
let parse_begin = char_parser(begin_char);
// Why cannot I move parser to preceded_by? <-- ERROR HERE
let precede = preceded_by(parse_begin, &mut parser);
let parse_final = char_parser(final_char);
followed_by(precede, parse_final)(input)
}
}
fn followed_by<Extracted, _Discard>(
mut parser_a: impl Parser<Extracted>,
mut parser_b: impl Parser<_Discard>
) -> impl FnMut(&str) -> ParseResult<&str, Extracted> {
move |input: &str| {
let (rest, new_value) = parser_a.parse(input)?;
let (rest, _) = parser_b.parse(rest)?;
Ok((rest, new_value))
}
}
fn preceded_by<Extracted, _Discard>(
mut parser_a: impl Parser<_Discard>,
mut parser_b: impl Parser<Extracted>
) -> impl FnMut(&str) -> ParseResult<&str, Extracted> {
move |input: &str| {
let (rest, _) = parser_a.parse(input)?;
parser_b.parse(rest)
}
}
// Region of external code, cannot modify
fn main() {
let my_combinator = delimited_by('a', 'b', char_parser('c'));
let mut final_combinator = external_combinator(my_combinator);
match final_combinator("data") {
Ok(_) => println!("OK"),
Err(_) => println!("Error")
}
}
当我尝试编译此演示时,出现以下错误。
error[E0277]: the trait bound `&mut impl Parser<Extracted>: Parser<_>` is not satisfied
--> src/main.rs:43:48
|
43 | let precede = preceded_by(parse_begin, &mut parser);
| ----------- ^^^^^^^^^^^ the trait `for<'a> FnMut(&'a str)` is not implemented for `impl Parser<Extracted>`, which is required by `&mut impl Parser<Extracted>: Parser<_>`
| |
| required by a bound introduced by this call
|
= note: required for `&mut impl Parser<Extracted>` to implement `for<'a> FnOnce(&'a str)`
note: required for `&mut impl Parser<Extracted>` to implement `Parser<_>`
--> src/main.rs:10:12
|
10 | impl<F, T> Parser<T> for F
| ^^^^^^^^^ ^
11 | where F: FnMut(&str) -> ParseResult<&str, T> {
| -------------------- unsatisfied trait bound introduced here
note: required by a bound in `preceded_by`
--> src/main.rs:63:24
|
61 | fn preceded_by<Extracted, _Discard>(
| ----------- required by a bound in this function
62 | mut parser_a: impl Parser<_Discard>,
63 | mut parser_b: impl Parser<Extracted>
| ^^^^^^^^^^^^^^^^^ required by this bound in `preceded_by`
help: consider further restricting this bound
|
37 | mut parser: impl Parser<Extracted> + for<'a> FnMut(&'a str)
| ++++++++++++++++++++++++
我尝试应用
+ for<'a> FnMut(&'a str)
但它会导致更多错误,最后编译器希望我更改 Parser<T>
但我不能这样做,因为在生产中 Parser<T>
是由外部代码提供的。
我有几个问题:
parser
或 delimited_by
的情况下将参数 preceded_by
从 dyn
传递到 Box
?external_combinator
中的特征吗?请记住,我无法更改外部区域中任何内容的签名或实现。parser
,请发布它,这也会有帮助。首先,请注意,在
delimited_by
中,&mut (impl SomeTrait)
并未实现 SomeTrait
。我们的第一个修改是删除 mut
和 &mut
:
fn delimited_by<Extracted>(
begin_char: char,
final_char: char,
parser: impl Parser<Extracted> // removed mut
) -> impl FnMut(&str) -> ParseResult<&str, Extracted> {
move |input: &str| {
let parse_begin = char_parser(begin_char);
let precede = preceded_by(parse_begin, parser); // removed &mut
let parse_final = char_parser(final_char);
followed_by(precede, parse_final)(input)
}
}
现在,我们遇到了第二个问题。当函数采用
impl SomeTrait
时(在本例中为 impl Parser<Extracted>
),Rust 默认假设没有额外的特征,如 Copy
或 Clone
。这意味着 parser
不能分别隐式或显式复制。然而,由于 delimited_by
返回一个每次执行时都需要 parser
的闭包,因此我们确实需要 parser
的多个副本或克隆。
我们可以添加一个
Clone
绑定到参数,这样我们就可以在每次闭包运行时 clone
它。我们还必须明确地说 char_parser
返回一个 Clone
able 函数。
fn char_parser(c: char) -> impl Fn(&str) -> ParseResult<&str, char> + Clone // Add Clone {
move |input: &str| {
let Some(rest) = input.strip_prefix(c) else {
return Err(format!("Input does not begin with {c}"));
};
Ok((rest, c))
}
}
fn delimited_by<Extracted>(
begin_char: char,
final_char: char,
parser: impl Parser<Extracted> + Clone // Add Clone
) -> impl FnMut(&str) -> ParseResult<&str, Extracted> {
move |input: &str| {
let parse_begin = char_parser(begin_char);
let precede = preceded_by(parse_begin, parser.clone()); // Add clone
let parse_final = char_parser(final_char);
followed_by(precede, parse_final)(input)
}
}