1

我正在使用解析器组合器Nom来编写 TOML 解析器。我遇到问题的解析器函数使用chrono crate 解析日期时间字符串。

fn offset_datetime<'a, E: ParseError<&'a str>>(input: &'a str) -> IResult<&'a str, TomlValue, E> {
    match DateTime::parse_from_rfc3339(input) {
        ParseResult::Ok(dt) => IResult::Ok(("", TomlValue::OffsetDateTime(dt))),
        ParseResult::Err(e) => {
            Err(Err::Error(Error::from_error_kind(input, ErrorKind::Fail)))
        }
    }
}

操场

在上面的代码中,我使用 解析一个字符串切片chrono::DatetTime::parse_from_rfc3339,它返回一个chrono::format::ParseResult. 然后,我正在匹配它,以便将其转换为正确的nom::IResult. ParseResult::Ok手臂很好,但我无法为ParseResult::Err. 这是我在编译上面的代码片段时遇到的错误:

error[E0308]: mismatched types
   --> src/parser.rs:193:28
    |
188 | fn offset_datetime<'a, E: ParseError<&'a str>>(input: &'a str) -> IResult<&'a str, TomlValue, E> {
    |                        - this type parameter
...
193 |             Err(Err::Error(Error::from_error_kind(input, ErrorKind::Fail)))
    |                            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected type parameter `E`, found struct `nom::error::Error`
    |
    = note: expected type parameter `E`
                       found struct `nom::error::Error<&str>`

ErrorfromError::from_error_kind是 Nom 自己的结构之一,它确实实现trait ParseError,就像E泛型指定的那样。为什么编译器不能识别这个?

4

1 回答 1

1

每当你给一个函数 ( offset_datetime) 一个泛型参数 ( E) 时,你就保证该函数可以适用于所有可能的类型E但受制于它的界限。您的函数签名承诺返回一个IResult错误类型E。但你不这样做;相反,您返回一个错误类型nom::error::Error(使用Error::from_error_kind)。

一种可能的解决方法是更改​​函数签名以返回函数体实际执行的具体错误类型:

fn offset_datetime<'a>(input: &'a str) -> IResult<&'a str, TomlValue, Error<&'a str>> {

另一种方法是更改​​函数体以使用签名声明的泛型类型:

        ParseResult::Err(e) => Err(Err::Error(E::from_error_kind(input, ErrorKind::Fail))),

请注意,它不是from_error_kind在具体类型nom::error::Error上调用,而是在类型变量上调用它E(由于E: ParseError绑定而具有该方法)。

我不熟悉如何nom正确使用,所以我不能告诉你哪个更合适。

于 2021-12-06T03:54:03.850 回答