4

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: "test@test.com".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: "test@test.com".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: "test@test.com".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: "test@test.com".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: "test@test.com".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: "test@test.com".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: "test@test.com".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: "test@test.com".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: "test@test.com".to_string(),
src/main.rs:26         addresses: &mut addresses
               ...
error: aborting due to previous error
Ronan Boiteau
  • 9,608
  • 6
  • 34
  • 56
Caballero
  • 11,546
  • 22
  • 103
  • 163
  • 1
    Your question doesn't have anything to do with mutability. Try very hard to reduce your problem to a [MCVE](/help/mcve) before posting. I understand it can be difficult, but I assure that it will help you understand problems better as well as get quicker answers ^_^. – Shepmaster Jun 16 '15 at 16:27
  • 2
    Read the answer, you're going to need that knowledge in the future, but for this particular example you probably don't want a `&mut Vec`. Just store a `Vec` in `User`. The user object doesn't borrow and modify someone else's address list, each has its own address list and owns it. –  Jun 16 '15 at 16:48
  • @Shepmaster I reduced it as much as I could. Your answer helped me to fix the reduced example, unfortunately it didn't work for my actual situation which is still producing the same error. Hopefully I can work it out now that I'm on the right track. Thanks. – Caballero Jun 16 '15 at 16:52
  • @Caballero no worries about not getting it all the way, so long as you tried ^_^. I used your example code and reordered the statements and it worked. Or did you mean your example not in the question? – Shepmaster Jun 16 '15 at 17:00
  • @Shepmaster I meant that in my real life situation which was vastly simplified into this question reordering didn't help, but I may be facing a different issue which I now need to try to digest. – Caballero Jun 16 '15 at 17:07
  • @Caballero perhaps! I look forward to your next question! ^_^ – Shepmaster Jun 16 '15 at 17:33
  • @Shepmaster Well in that case do you mind taking a look at my update? This is actually closer to my problem and that's how I should have formed it from the beginning. – Caballero Jun 16 '15 at 17:38
  • Please look [here](http://stackoverflow.com/questions/29428227/return-local-string-as-slice), [here](http://stackoverflow.com/questions/29869764/how-do-i-return-a-vector-created-using-a-for-loop) and [here](http://stackoverflow.com/questions/27275007/converting-from-string-to-str-with-a-different-lifetime), and through the links in these questions and answers. Hopefully it will clarify what's the problem here (and, for example, why using a lifetime parameter like in `fn get_users<'a>() -> Vec>` is unsound. – Vladimir Matveev Jun 16 '15 at 18:16
  • These questions are not exact duplicates, however, so I'm reluctant to mark this question as one. – Vladimir Matveev Jun 16 '15 at 18:16
  • @VladimirMatveev Thanks. It looks like these questions mostly deal with strings and still the general answer is "impossible", so I'm guessing since my situation is even more complicated I can file this under "definitely impossible"? – Caballero Jun 16 '15 at 18:27
  • 2
    It doesn't work like that. This whole set of problems stems from one source, the basic concepts of ownership and borrowing, and all of these questions (including yours) are just about different applications of them. Here you're trying to return a borrowed reference to an owned structure (`Vec
    `) from a function, but this owned structure is owned by the stack frame of the function, and when this function returns, this structure is destroyed, and the returned reference would become dangling if it was allowed to return it. This is essentially the same thing as in the other questions.
    – Vladimir Matveev Jun 16 '15 at 19:37
  • possible duplicate of [Returning a struct containing mutable values](http://stackoverflow.com/questions/29598264/returning-a-struct-containing-mutable-values) – Matthieu M. Jun 17 '15 at 06:07

1 Answers1

7

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);
}
Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366