Conflicting lifetime parameters: Trait vs. Struct

I want a struct that holds a &str. I have a trait Parse that wants to parse a &str and return a T.

I'm now lost in a twisty maze of lifetimes, all unlike. The basic issue is that my parse method and my struct both want to hold on to declared lifetimes, and I can provide no guarantees to the complier that the lifetimes are compatible. At the same time, I can't tell the complier that parse want to return a borrow that lasts as long as the struct.

pub trait Parse<T> {
    fn parse<'a>(v: &'a str) -> Result<T,()>;
}

pub struct Field<'a> {
    pub name: Fields,
    pub value: &'a str
}

impl<'a> Parse<Field<'a>> for Field<'a> {
    fn parse<'b>(v: &'b str) -> Result<Self,()> {
        let fields: Vec<&'b str> = v.split(":").collect();
        if fields.len() < 2 {
            Err(())
        } else {
            Ok(Field { name: Fields::from(fields[0]),
                       value: fields[1]})
        }
    }
}


lib.rs:66:35: 66:44 error: cannot infer an appropriate lifetime for automatic coercion due to conflicting requirements
lib.rs:66                            value: fields[1]})
                                            ^~~~~~~~~
lib.rs:60:9: 68:10 help: consider using an explicit lifetime parameter as shown: fn parse(v: &'a str) -> Result<Self, MailError>

Note that the error message asks for an incorrect and invalid fix.

I've tried to cast the lifetime to 'a, but that gives me an outlives error.

The trait method being generic over the lifetime means you can't make any assumptions about that lifetime in the implementation. I guess you could make the trait have the parameter as well:

pub trait Parse<'a, T> {
    fn parse(v: &'a str) -> Result<T,()>;
}

pub struct Field<'a> {
    pub value: &'a str,
}

impl<'a> Parse<'a, Field<'a>> for Field<'a> {
    fn parse(v: &'a str) -> Result<Self,()> {
        Ok(Field { value: v })
    }
}

Also note that

fn parse<'a>(v: &'a str) -> Result<T,()>

is equivalent to

fn parse(v: &str) -> Result<T,()>

due to lifetime elision.

What about Rust Playground ?

Well golly -- making the trait have a lifetime type parameter works. (Now I need to figure out why it works...)

Thanks!

There needs to be a parameter denoting the lifetime of v bound to the lifetime of the struct somehow. A parameter on the method would be unbounded but a parameter on the trait allows us to require (Parse<'a, ...> for Field<'a>) that the lifetime of Field is the same as that of v.

Technically, we only need v to outlive Field, as in

pub trait Parse<'a, T> {
    fn parse(v: &'a str) -> Result<T,()>;
}

pub struct Field<'a> {
    pub value: &'a str,
}

impl<'a, 'b: 'a> Parse<'b, Field<'a>> for Field<'a> {
    fn parse(v: &'b str) -> Result<Self,()> {
        Ok(Field { value: v })
    }
}

This will allow using a string literal, which is a &'static str, to get a shorter lived Field.

T seems redundant here BTW, the trait would achieve the same with just the lifetime parameter and Result<Self, ()> return type.

1 Like