简体   繁体   中英

Rust compiler not recognizing a generic trait bound implemented for a struct

I am using Nom , the parser combinator, to write a TOML parser. The parser function I am having trouble with parses a date time string using the chrono crate. Here's the code ( playground link ):


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)))
        }
    }
}

In the code above, I am parsing a string slice using chrono::DatetTime::parse_from_rfc3339 , which returns a chrono::format::ParseResult . Then, I am matching it so I can convert it to a proper nom::IResult . The ParseResult::Ok arm is fine, but I cannot write the correct code for ParseResult::Err . Here's the error I get when compiling the code snippet above:

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>`

The Error from Error::from_error_kind is one of Nom's own structs, which does implement the ParseError trait, just as the E generic specifies. Why cannot the compiler recognize this?

Whenever you give a function ( offset_datetime ) a generic parameter ( E ), you are promising that the function can work for every possible type that E could be, subject to its bounds. Your function signature promises to return an IResult with error type E . But you do not do that; instead, you return one with error type nom::error::Error (using Error::from_error_kind ).

One possible fix is to change the function signature to return the concrete error type that the function body actually does:

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

Another one would be to change the function body to use the generic type the signature claims:

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

Note that instead of calling from_error_kind on the concrete type nom::error::Error , it's calling it on the type variable E (which has that method because of the E: ParseError bound).

I'm not familiar with how to use nom properly, so I can't tell you which of these is more appropriate.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM