I spent a while on this while trying to implement an interator:
$ rustc check.rs
check.rs:29:5: 31:6 error: method `next` has an incompatible type for trait: expected concrete lifetime, found bound lifetime parameter [E0053]
check.rs:29 fn next(&mut self) -> Option<&Node<'a>> {
check.rs:30 Some(&self.root.nodes[0])
check.rs:31 }
check.rs:29:45: 31:6 note: expected concrete lifetime is the lifetime 'a as defined on the block at 29:44
check.rs:29 fn next(&mut self) -> Option<&Node<'a>> {
check.rs:30 Some(&self.root.nodes[0])
check.rs:31 }
error: aborting due to previous error
After reading the documentation, I had absolutely no idea what concrete or bound lifetime parameters are. Too add to my confusion, consider:
fn next(&mut self) -> Option<&Node<'a>> {
fn next(&'a mut self) -> Option<&Node<'a>> {
fn next(&'a mut self) -> Option<&'a Node<'a>> {
fn next(&mut self) -> Option<&'a Node<'a>> {
The first three give the same error message, the final one compiles. The full fixed code (n-ary tree with a useless iterator):
pub struct Node<'a> {
pub val: &'a str,
pub nodes: Vec<Node<'a>>,
}
impl<'a> Node<'a> {
fn iter(&'a self) -> NodeIter<'a> {
NodeIter {
root: self,
cur: 0,
}
}
}
struct NodeIter<'a> {
root: &'a Node<'a>,
cur: uint,
}
impl <'a> Iterator<&'a Node<'a>> for NodeIter<'a> {
fn next(&mut self) -> Option<&'a Node<'a>> {
Some(&self.root.nodes[0])
}
}
Going off topic a bit: per prasoon2211, I’d really like the lifetime guide to go into more detail (In addition to ‘+’ and concrete and bound lifetimes, I can’t see any mention of ‘:’), either with some more complex examples or theory. For example I don’t know the difference is between all parameters being 'a and the following which also compiles (something to do with the lifetime of the reference being defined by the caller?):
impl<'b, 'c> Iterator<&'b Node<'c>> for NodeIter<'c> {
fn next<'a>(&mut self) -> Option<&'a Node<'c>> {
let tok: &'a Node<'c> = &self.root.nodes[0];
return Some(tok);
}
}
Edit: after playing some more, it seems that putting 'a everywhere is fine…if you’re then willing to accept the viral effect of having to annotate all your functions when you want an iterator (because it asserts an unnecessarily strong condition for the lifetime of values). By adding appropriate additional lifetimes I’m able to relax the conditions to get an iterator in an unannotated function.