Skip to content
Select theme

How to borrow one field of a struct

Short answer: Borrow the field, not the struct: &player.name borrows only that field, so a &mut player.score can be alive at the same time. The borrow checker tracks the fields of a struct separately — until a method call, whose self is the whole struct. player.double() borrows all of player, no matter which fields double actually touches.

Start from a fresh project — cargo new borrow-field, then replace src/main.rs with the whole of each file below.

Ada has 100 points

A shared borrow of player.name and an exclusive borrow of player.score are alive at the same time, and the compiler approves. They point at different fields, so they never overlap: this is called a disjoint borrow. The rule “one mutable borrow, or many shared ones” applies per place — and a field is its own place, separate from every other field and from the struct as a value.

The same split works through a function. transfer takes two &mut u32 values, and at the call site they borrow two different fields:

score 0, bonus 50

Two exclusive borrows of player are alive during the call, and it still compiles — because one covers player.score and the other covers player.bonus. Inside transfer there is no way to tell that the two integers came from the same struct; the splitting happened where the borrows were written, in the caller.

Point both arguments at the same field and the split is gone:

error[E0499]: cannot borrow `player.score` as mutable more than once at a time
--> src/main.rs:18:33
|
18 | transfer(&mut player.score, &mut player.score);
| -------- ----------------- ^^^^^^^^^^^^^^^^^ second mutable borrow occurs here
| | |
| | first mutable borrow occurs here
| first borrow later used by call
For more information about this error, try `rustc --explain E0499`.

The two arguments now borrow the same place, so one of them has to lose. The diagnostic says it plainly: the first borrow of player.score is still live — it is on its way into the call — when the second one starts.

Field borrows get one big exception, and it looks arbitrary at first. Here double only touches self.score, one field — yet the call conflicts with a borrow of name:

error[E0502]: cannot borrow `player` as mutable because it is also borrowed as immutable
--> src/main.rs:19:5
|
18 | let name = &player.name;
| ------------ immutable borrow occurs here
19 | player.double();
| ^^^^^^^^^^^^^^^ mutable borrow occurs here
20 | println!("{name}");
| ---- immutable borrow later used here
For more information about this error, try `rustc --explain E0502`.

The reason is in the signature, not the body. player.double() means Player::double(&mut player): the method takes &mut self, and self is the whole Player, so the call borrows every field at once. What a method borrows is decided by its signature — the compiler does not split a borrow based on which fields the body happens to use. Inside double, self.score borrows through self, which already owns the exclusive borrow of everything.

The fix is the last-use rule from the previous article: the borrow of player.name ends at its last read, so put that read before the call.

Ada
Ada has 20 points

The method call sits after the last use of name, so the borrows never overlap. When the field borrow genuinely has to stay live across a method call, the way out is to stop borrowing the whole struct — pass the field, or hand out the value — which is the subject of the next article.