Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Lifetime of a mutable element in struct

Tags:

rust

How can I define a mutable element in a struct? If I have the following example:

struct User<'a> {
    reference: String,
    email: String,
    addresses: &'a mut Vec<Address>
}

struct Address {
    street: String,
    city: String
}

fn main() {

    let mut users = Vec::new();
    users.push(User {
        reference: "ref".to_string(),
        email: "[email protected]".to_string(),
        addresses: &mut Vec::new()
    });

}

...it produces an error:

src/main.rs:18:19: 18:29 error: borrowed value does not live long enough
src/main.rs:18      addresses: &mut Vec::new()
                                    ^~~~~~~~~~
src/main.rs:14:29: 21:2 note: reference must be valid for the block suffix following statement 0 at 14:28...
src/main.rs:14  let mut users = Vec::new();
src/main.rs:15  users.push(User {
src/main.rs:16      reference: "ref".to_string(),
src/main.rs:17      email: "[email protected]".to_string(),
src/main.rs:18      addresses: &mut Vec::new()
src/main.rs:19  });
               ...
src/main.rs:15:2: 19:5 note: ...but borrowed value is only valid for the statement at 15:1
src/main.rs:15  users.push(User {
src/main.rs:16      reference: "ref".to_string(),
src/main.rs:17      email: "[email protected]".to_string(),
src/main.rs:18      addresses: &mut Vec::new()
src/main.rs:19  });
src/main.rs:15:2: 19:5 help: consider using a `let` binding to increase its lifetime
src/main.rs:15  users.push(User {
src/main.rs:16      reference: "ref".to_string(),
src/main.rs:17      email: "[email protected]".to_string(),
src/main.rs:18      addresses: &mut Vec::new()
src/main.rs:19  });
error: aborting due to previous error

...and if I take compiler's suggestion help: consider using a let binding to increase its lifetime:

fn main() {

    let mut users = Vec::new();
    let mut addresses = Vec::new();
    users.push(User {
        reference: "ref".to_string(),
        email: "[email protected]".to_string(),
        addresses: &mut addresses
    });

}

...I still get a similar error:

src/main.rs:19:19: 19:28 error: `addresses` does not live long enough
src/main.rs:19      addresses: &mut addresses
                                    ^~~~~~~~~
src/main.rs:14:29: 22:2 note: reference must be valid for the block suffix following statement 0 at 14:28...
src/main.rs:14  let mut users = Vec::new();
src/main.rs:15  let mut addresses = Vec::new();
src/main.rs:16  users.push(User {
src/main.rs:17      reference: "ref".to_string(),
src/main.rs:18      email: "[email protected]".to_string(),
src/main.rs:19      addresses: &mut addresses
               ...
src/main.rs:15:33: 22:2 note: ...but borrowed value is only valid for the block suffix following statement 1 at 15:32
src/main.rs:15  let mut addresses = Vec::new();
src/main.rs:16  users.push(User {
src/main.rs:17      reference: "ref".to_string(),
src/main.rs:18      email: "[email protected]".to_string(),
src/main.rs:19      addresses: &mut addresses
src/main.rs:20  });
               ...
error: aborting due to previous error

What's the issue here?

UPDATE: So this situation is actually closer to my problem:

struct User<'a> {
    reference: String,
    email: String,
    addresses: &'a mut Vec<Address>
}

struct Address {
    street: String,
    city: String
}

fn main() {

    let mut users = get_users();

}

fn get_users<'a>() -> Vec<User<'a>> {

    let mut addresses = Vec::new();
    let mut users = Vec::new();
    users.push(User {
        reference: "ref".to_string(),
        email: "[email protected]".to_string(),
        addresses: &mut addresses
    });

    users

}

...and it's causing this error:

src/main.rs:26:25: 26:34 error: `addresses` does not live long enough
src/main.rs:26         addresses: &mut addresses
                                       ^~~~~~~~~
src/main.rs:19:37: 31:2 note: reference must be valid for the lifetime 'a as defined on the block at 19:36...
src/main.rs:19 fn get_users<'a>() -> Vec<User<'a>> {
src/main.rs:20 
src/main.rs:21  let mut addresses = Vec::new();
src/main.rs:22     let mut users = Vec::new();
src/main.rs:23     users.push(User {
src/main.rs:24         reference: "ref".to_string(),
               ...
src/main.rs:21:33: 31:2 note: ...but borrowed value is only valid for the block suffix following statement 0 at 21:32
src/main.rs:21  let mut addresses = Vec::new();
src/main.rs:22     let mut users = Vec::new();
src/main.rs:23     users.push(User {
src/main.rs:24         reference: "ref".to_string(),
src/main.rs:25         email: "[email protected]".to_string(),
src/main.rs:26         addresses: &mut addresses
               ...
error: aborting due to previous error
like image 277
Caballero Avatar asked Mar 16 '23 17:03

Caballero


1 Answers

I know this has been answered before, but I can't find it... feel free to mark this as duplicate if you find it.

The problem is that you are attempting to store a reference in a container that will outlive the reference. Here's a MCVE of your problem:

fn main() {
    let mut things = vec![];
    let a = 42;
    things.push(&a);
}

Items are dropped in the reverse order they are created, so a is dropped before things. However, things has a reference to a, which means that there would be a point in time where there's a dangling reference, which Rust doesn't allow. Reorder your statements:

fn main() {
    let a = 42;
    let mut things = vec![];
    things.push(&a);
}
like image 182
Shepmaster Avatar answered Mar 18 '23 07:03

Shepmaster