So again I am struggling with lifetimes.
I have a basic example below
I have a pipeline object that contains two vectors. The first holds Element's which is a trait and the second
ElementPads which are normal structs. I have added lifetimes on the Pipeline struct for both types. I also have two functions one to find a Element and one to find a ElementPad.
This throws the error
cannot infer an appropriate lifetime for lifetime parameter 'a
due to conflicting requirements
at this line
let element : &Element = try!(self.find_element(name));
Why is this ?
the return on that function is
PipelineResult<(&'a Element, &'b ElementPad)>
so should the compiler be able to infer this ?
Thanks
pub type ElementResult<T> = Result<T, String>;
pub struct ElementPad {
pub name : String,
}
pub trait Element {
fn get_name(&self) -> String;
fn get_pad(&self, name : &str) -> ElementResult<&ElementPad>;
}
pub type PipelineResult<T> = Result<T, String>;
pub struct Pipeline<'a, 'b> {
elements : Vec<&'a Element>,
element_pads : Vec<&'b ElementPad>,
}
impl<'a, 'b> Pipeline<'a, 'b> {
fn find_element(&self, name : &str) -> PipelineResult<&'a Element> {
let option = self.elements.iter().find(|&r| r.get_name() == name.to_string());
match option {
Some(e) => Ok(*e),
None => {
warn!("Element with name {} not found in pipeline", name);
return Err("Error".to_string())
},
}
}
// Comment this and things are fine
fn find_element_pad(&self, name : &str, pad_name : &str) -> PipelineResult<(&'a Element, &'b ElementPad)> {
let element : &Element = try!(self.find_element(name));
let pad = try!(element.get_pad(pad_name));
Ok((element, pad))
}
}
Ok, I tried this:
basically, I think you need this:
fn find_element_pad<'s>(&'s self, name : &'a str, pad_name : &str)
-> PipelineResult<(&'a Element, &'b ElementPad)>
where 's: 'b
Because the lifetime of the actual Pipeline struct needs to be taken into consideration when returning it's inner references. The 's: 'b bounds the s to live at least as long as b. In my playground example I also bounded 'b: 'a so that s lives longer than b lives longer than a...
Thanks a lot.
Makes sense.
Out of curiosity was that just experience or did you infer something from the error I didn't ?
Experience mostly. The error is hard to grok from the report that the compiler gives. So what I do is sit back sometimes and try and understand what it is that is happening... so reading the code I basically was like, is there more information that I can give the compiler, and what is missing. In this context I noticed that (if I understood your code/intentions properly!) that 'b
would always be derived from 'a
and the the function find_element_pad()
wasn't declaring the actual struct's lifetime itself, but it was implicitly getting one from the &self
.
Honestly, I've never tried code like you put up before, so it was a fun challenge to see if I could figure it out!
Sorry to bother you again but wonder as you said you have not tried code like this that its style is not very Rust like.
I updated vour example
It basically adds a mut method to insert into the vector and added a run method.
I just get errors like
"second mutable borrow occurs here" and mixing borrow errors that I usually get with self methods.
How are errors like this dealt with or does it suggest a problem with the design ?
Thanks
So I have to ask a question at this point. Who do you plan on owning this data? I mean, you have a lot of borrowing going on, but it might be better if the Element
had owned String
s, i.e. "string".to_string()
Anyway, the crux of your current issue is that the caller because the &str
s are borrowed, and those borrows cause the mutable borrow to live longer than the initial add call. It would be better if on insertion, it was a fully owned object, then you could borrow it back where necessary...
does that make sense?
Yeah Thanks that does make sense.
I think you have to think more returning references from structs / objects.
In the end I have made ElementPad implement clone which seems reasonable as they are simple objects.
This seems to correct things and makes some of the other code easier to understand.
Understanding a little more each day
Thanks
1 Like