为什么元组在nom库中需要类型注释



我正在rust中使用nom库编写一个解析器。在使用tuple时,我遇到了一个问题。这个片段运行良好:

use std::str;
use nom::bytes::complete::take_while1;
use nom::bytes::complete::{tag, take_while};
use nom::character::complete::{char, multispace0};
use nom::sequence::tuple;
use nom::IResult;

fn identifier(input: &str) -> IResult<&str, &str> {
take_while1(is_ascii_alphanumeric)(input)
}
fn parameter_separator(input: &str) -> IResult<&str, &str> {
let my_parser = tuple((multispace0, char(','), identifier));
let (input, _) = multispace0(input)?;
let (input, _) = char(',')(input)?;
let (input, _) = multispace0(input)?;
Ok((input, ""))
}

但是当用multispace0解析器替换identifier解析器时,编译器要求我键入注释my_parser


fn parameter_separator(input: &str) -> IResult<&str, &str> {
let parser = tuple((multispace0, char(','), multispace0));
let (input, _) = multispace0(input)?;
let (input, _) = char(',')(input)?;
let (input, _) = multispace0(input)?;
Ok((input, ""))
}
49  |   let parser = tuple((multispace0, char(','), multispace0));
|       ------   ^^^^^ cannot infer type for type parameter `E` declared on the function `tuple`
|       |
|       consider giving `parser` a type

有什么区别?为什么第二个会引发错误?

tuple有一个泛型参数E,它必须是ParserError<I>的实例。

在第二个函数中,编译器无法从上下文推断tupleE参数的类型。在tuple((multispace0, char(','), multispace0))(input)中,传递给tuple的参数都没有提供E可能是什么的足够信息。因此,您会看到以下错误:

pub fn tuple<I, O, E: ParseError<I>, List: Tuple<I, O, E>>(
^^^^^^^^^^^^^ required by this bound in `tuple`

您的第一个示例之所以有效,是因为identifier的类型IResult<&str, &str>本身扩展为Result<(&str, &str), nom::Err<nom::error::Error<&str>>>

这允许编译器在tuple()调用中实例化Enom::Err<nom::error::Error<&str>>

因此,如果您为multispace0定义一个别名,而不指定E,则代码将正确编译:

fn narrowed_multispace0(input: &str) -> Result<(&str, &str), nom::Err<nom::error::Error<&str>>> {
multispace0(input)
}
let _ = tuple((narrowed_multispace0, char(','), multispace0))(input);

Rust实现了执行双向类型推理的Hindley-Milner类型系统。这使得即使从函数的结果类型也可以推断出E,如下例所示:

fn parameter_separator(input: &str) -> IResult<&str, &str> {
map(  // To map (&str, &str, &str)` onto `&str`
tuple((multispace0, char(','), multispace0)),
|_| "test"
)(input)
}

相关内容

  • 没有找到相关文章

最新更新