Lifetime issue with one needing to outlive another

Folks,

I'm new to Rust and I'm playing with it and found a problem I can't seem to solve by myself or find the answer. I create the small repro below that's a proxy to my larger program. I'm looking for suggestions on what to do, please, any pointers will help. Thank you!

#[derive(Debug)]
struct A;

#[derive(Debug)]
struct B<'a> {
    refa: &'a A,
}

impl B<'_>
{
    pub fn new_b<'a>(ra: &'a A) -> B<'a>
    {
        B { refa: ra }
    }
}

#[derive(Debug)]
struct C<'a> {
    name: String,
    vecb: Vec<B<'a>>,
}

impl C<'_>
{
    pub fn new_c<'a,'b>(n: &'a str) -> C<'b>
    {
        C { name: n.to_string().clone(), vecb: Vec::new() }
    }

    pub fn populate_vecb<'a,'b>(&'a mut self, veca: &'b Vec<A>)
        where 'b: 'a
    {
        for _ in 0..4 {
            let newb = B::new_b(&veca[0]);
            self.vecb.push(newb);
        }
    }

    pub fn get_vecc<'a,'b>(veca: &'b Vec<A>) -> Vec<C<'a>>
        where 'b: 'a
    {
        let mut vecc: Vec<C> = Vec::new();

        for _ in 0..7 {
            let mut newc = C::new_c(&"bla");
            newc.populate_vecb(veca);
            vecc.push(newc);
        }

        vecc
    }
}

fn main() {
    let mut veca: Vec<A> = Vec::new();
    for _ in 0..5 {
        veca.push(A{});
    }

    let vecc = C::get_vecc(&veca);
    println!("{:?}", vecc);
}

The error message I get is below:

error: lifetime may not live long enough
  --> src/main.rs:35:13
   |
30 |     pub fn populate_vecb<'a,'b>(&'a mut self, veca: &'b Vec<A>)
   |                             --  ------------ has type `&mut C<'1>`
   |                             |
   |                             lifetime `'b` defined here
...
35 |             self.vecb.push(newb);
   |             ^^^^^^^^^^^^^^^^^^^^ argument requires that `'b` must outlive `'1`

Be more consistent with your lifetime names (and give them meaningful names where practical).

Then line up the lifetimes in the implementation, e.g. make the lifetimes of references to As the same.

1 Like

Whoops, forgot the link.

2 Likes
// You have to name the lifetime of B's in C, let's call it 'c
impl<'c> C<'c> {

    // veca must live (at least) as long as 'c, because we're referencing it in our struct
    //The lifetime in &'_ mut self can be elided
    pub fn populate_vecb(&mut self, veca: &'c Vec<A>)
    {
        for _ in 0..4 {
            let newb = B::new_b(&veca[0]);
            self.vecb.push(newb);
        }
    }
}

...and this already works.

Some unrelated notes:

  • You don't need .to_string().clone()! str::to_string already clones into a new allocation, an extra clone is unnecessary.
  • You almost never need to do this: <'a, 'b> where 'a: 'b. Just replace 'b's with 'a's, and variance still allows you to have different lifetimes.
1 Like

@quinedot and @FZs , thank you very much. That was fast and both solutions work. I also appreciate the tips on how to do things better!

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.