我使用
alt
的 nom
函数为机器人命令构建解析器,即示例中的 parse_command
。
# src/main.rs
use nom::{
IResult,
bytes::complete::{tag},
branch::alt,
combinator::map,
};
#[derive(Debug, PartialEq)]
pub enum Command {
Foo(),
Bar(),
}
pub fn parse_command(input: &str) -> IResult<&str, Command> {
alt((
parse_foo,
parse_bar,
))(input)
}
fn parse_foo(input: &str) -> IResult<&str, Command> {
map(tag("!bar"), |_| Command::Bar())(input)
}
fn parse_bar(input: &str) -> IResult<&str, Command> {
map(tag("!foo"), |_| Command::Foo())(input)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_parse_bar() {
let s = "!bar";
let (_, result) = parse_command(s).unwrap();
assert_eq!(result, Command::Bar());
}
#[test]
fn test_parse_foo() {
let s = "!foo";
let (_, result) = parse_command(s).unwrap();
assert_eq!(result, Command::Foo());
}
}
这个效果很好。然而,在阅读 examples 时,我的印象是我可以更新
parse_bar
和 parse_foo
函数的签名,如下所示:
use nom::{
Parser,
error::Error,
};
fn parse_foo<'a>() -> impl Parser<&'a str, Command, Error<&'a str>> {
map(tag("!bar"), |_| Command::Bar())
}
fn parse_bar<'a>() -> impl Parser<&'a str, Command, Error<&'a str>> {
map(tag("!foo"), |_| Command::Foo())
}
但是,编译器对我尖叫:
error[E0593]: function is expected to take 1 argument, but it takes 0 arguments
--> src/main.rs:18:9
|
17 | alt((
| --- required by a bound introduced by this call
18 | parse_foo,
| ^^^^^^^^^ expected function that takes 1 argument
...
24 | fn parse_foo<'a>() -> impl Parser<&'a str, Command, Error<&'a str>> {
| ------------------------------------------------------------------- takes 0 arguments
|
= note: required for `fn() -> impl Parser<&str, Command, nom::error::Error<&str>> {parse_foo::<'_>}` to implement `Parser<_, _, _>`
= note: required for `(fn() -> impl Parser<&str, Command, nom::error::Error<&str>> {parse_foo::<'_>}, fn() -> impl Parser<&str, Command, nom::error::Error<&str>> {parse_bar::<'_>})` to implement `nom::branch::Alt<_, _, _>`
note: required by a bound in `alt`
--> /home/pamplemousse/.cargo/registry/src/index.crates.io-6f17d22bba15001f/nom-7.1.3/src/branch/mod.rs:47:49
|
47 | pub fn alt<I: Clone, O, E: ParseError<I>, List: Alt<I, O, E>>(
| ^^^^^^^^^^^^ required by this bound in `alt`
[... and same error for `parse_bar`...]
我对使用
Parser
特性来实现此类功能的期望是否错误?如果没有,我错过/误解了什么以便我更新的代码可以工作?
您的第二个示例失败了,没有显示对
parse_command
的调用。如果它与第一个有效的调用完全相同,那么问题在于您没有调用函数来返回实际的 Parser
实现,而是将 fn
传递给它期望的 Parser
实现.
所以修复应该是:
pub fn parse_command(input: &str) -> IResult<&str, Command> {
alt((
parse_foo(),
parse_bar(),
))(input)
}
需要明确的是,区别在于
parse_foo()
与 parse_foo
,与 parse_bar
类似。