Sometimes we cannot compile a Rust program because it requires a lifetime specifier. This can be complicated to resolve, but occasionally a small bit of syntax can fix the program.
When using references to other data in memory, we need lifetimes to ensure everything is still present in memory when we go to use the reference. The lifetime ensures the reference is valid.
This program has a Tree struct
, and a Forest struct
. Each Forest references a slice of Trees. This means that for the Forest to be valid, The trees must still exist in memory.
struct
is used inside the Forest struct
. It is just a normal struct
with no special issues.struct
. The Trees are valid at least as long as the Forest.// Part 1: the struct that is referenced by another struct. struct Tree { height: usize, has_leaves: bool, } // Part 2: a struct that contains a slice of references to another struct, with lifetime parameter. struct Forest<'a> { trees: &'a [Tree], } fn main() { // Part 3: create Tree structs, and add them to the Forest struct, which references them. let t1 = Tree { height: 10, has_leaves: true }; let t2 = Tree { height: 12, has_leaves: true }; let forest = Forest { trees: &vec![t1, t2] }; // Part 4: display all referenced structs in the Forest. for tree in forest.trees { println!("{} {}", tree.height, tree.has_leaves); } }10 true 12 true
When we have a reference to another allocated struct
within a struct
, we will usually need a lifetime specifier. This must be placed on both the struct
itself, and the reference.
error[E0106]: missing lifetime specifier --> src/main.rs:9:12 | 9 | trees: &[Tree], | ^ expected named lifetime parameter | help: consider introducing a named lifetime parameter
With lifetime specifiers, the compiler has a way to ensure that references remain valid as long as needed. This means we cannot access invalid references and thus break
memory safety.