Borrowing rules about self

Hello,
I’m trying to run this code

struct Member<'a> {
    name: &'a str,
    age: u8,
}

impl<'a> Member<'a> {
    fn modify_name(&'a mut self, name: &'a str) {
        self.name = name;
    }

    fn modify_age(&'a mut self, age: u8) {
        self.age = age;
    }
}

fn main() {
    let l = &mut Member {
        name: "Leo",
        age: 10,
    };
    l.modify_name("Tom");
    l.modify_age(9);
}

Get an error:

  --> src/bin/test.rs:22:5
   |
21 |     l.modify_name("Tom");
   |     - first mutable borrow occurs here
22 |     l.modify_age(9);
   |     ^
   |     |
   |     second mutable borrow occurs here
   |     first borrow later used here

Does this mean that When I call my modify_name/modify_age methods, it borrows a whole variable it implemented for?

This is a simplified example. In my project, there is a need to modify the same/different field of the same instance multiple times. How should this be handled in Rust?

If we look at this:

impl<'a> Member<'a> {
    fn modify_name(&'a mut self, name: &'a str) {
        self.name = name;
    }
}

The type of &mut self is &'a mut Member<'a>. When you call this method, it forces you to mutably borrow the Member<'a> for the lifetime 'a -- that's the entire lifetime of the data structure. Once you call this method, you'll never be able to do anything else with the data structure, because it will still be mutably (exclusively) borrowed.

In short, &'a mut Something<'a> is an anti-pattern you should avoid.

The fix is to accept a lifetime on &mut self that is shorter than 'a -- arbitrarily shorter. You can do this by simply leaving the 'a off of the &mut:

impl<'a> Member<'a> {
    fn modify_name(&mut self, name: &'a str) {
        self.name = name;
    }
}

Playground.


This is also true (but wasn't the source of your errors).

4 Likes

Yes, you've explicitly made it so.

This means the struct Member can be alive up to some lifetime 'a

so it's ok to store some references which is alive for the lifetime 'a.

Within this impl block the Member is alive up to 'a

and this method borrows the Self - which is Member<'a> - for the lifetime 'a, which is the whole lifetime of the Member<'a>.

So how can it be fixed? Easiest solution is to change methods to not take &'a mut self. Just take &mut self which means its lifetime is not tied to the 'a.

But the real problem would be that you're storing references inside of the struct without feeling confident with the lifetime rules. In most cases structs should own the content of its fields. Why don't you store the String instead?

4 Likes

@quinedot @Hyeonu
Thank you very much for your reply, let me figure out this problem.

I understand what @Hyeonu 's meant, and in this simplified example, I totally agree. But in my real project, some structure fields need to store data that is more complex than String. If I don't use references in all structures, it will take up more resources, including data synchronization.

I should still further improve my understanding of the lifetime, thank you for your help.

You can use Arc(or Rc if it compiles) to share single owned value across multiple point. From my experience sometimes it helps much.

Out of curiosity, is there a lint in rustc or clippy for this?

I doubt it, but it's a good question. It's certainly a common point of confusion.

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.