Introduction
Moving a String transfers ownership, but many functions only need temporary access. Rust calls that temporary access a borrow and represents it with a reference.
You will complete a prepared guest-list program in three small stages: inspect owned text through a shared reference, intentionally observe why shared access cannot modify it, and then make one controlled update through a mutable reference. The final output will prove that main still owns and can use the list.
Inspect Data Through a Shared Reference
In this step, you will lend a function read-only access to a String instead of moving ownership into it.
Enter the prepared Cargo project and open its source:
cd /home/labex/project/guest-borrowing
nano src/main.rs
The setup created the complete project and left one placeholder in the call to inspect_guests. Its parameter type is &String. The & means “a reference to a String”: the function may temporarily view the value, but it does not become the owner.
Replace only /* Step 1: borrow guest_list */ with &guest_list, so the call becomes:
inspect_guests(&guest_list);
Here, &guest_list creates a shared reference. Shared means read-only access may be shared without transferring the String itself.
Save with Ctrl+O, press Enter, and exit with Ctrl+X. Run the program:
cargo run --quiet
The output should be:
Inspecting: Ari, Bo
Caller still owns: Ari, Bo
Before update: Ari, Bo
Updated: Ari, Bo
The first line comes from the borrowed reference. The second line is the important ownership evidence: after inspect_guests returns, main can still use guest_list. The update function also reads the current value, but it does not change it yet.
Observe the Shared-Reference Limit
In this step, you will intentionally try to modify the String through a shared reference. The failed compiler check is expected and gives you evidence for Rust's borrowing rule.
Open the source again:
nano src/main.rs
Inside add_guest, remove only the leading // from the prepared line so it becomes:
list.push_str(", Mina");
The push_str method appends text to a String, so it requires permission to modify the value. However, list currently has type &String, which grants shared, read-only access.
Save and exit. Before checking, predict the result: the compiler should reject the attempted modification because a shared reference cannot provide mutable access.
Run the check. Failure is expected:
cargo check
Find these stable parts of the diagnostic:
error[E0596]: cannot borrow `*list` as mutable, as it is behind a `&` reference
...
consider changing this to be a mutable reference
The *list wording refers to the String reached through the reference. Rust is not saying the String can never change; it is saying this particular &String does not carry permission to change it. You will grant controlled mutable access in the next step.
Update Through a Mutable Reference
In this step, you will give add_guest temporary, exclusive permission to modify the caller's String.
A mutable reference has the form &mut T. A useful beginner rule is many readers or one writer at a time: shared references allow reading, while one mutable reference grants temporary exclusive write access. That exclusivity prevents two parts of a program from changing the same value unexpectedly.
Open the file:
nano src/main.rs
Make three focused edits:
- Change the
add_guestparameter from&Stringto&mut String. - Add
mutto the binding so it readslet mut guest_list = .... - Change the
add_guestcall from&guest_listto&mut guest_list.
The completed function signature and call should have these forms:
fn add_guest(list: &mut String) {
add_guest(&mut guest_list);
The two uses of mut have connected but different jobs. let mut guest_list says the owned value is allowed to change. &mut guest_list then creates one temporary mutable reference that lends exclusive write access to add_guest for the duration of the call.
Save and exit, then check the repair:
cargo check
A Finished result without E0596 means the permissions now agree. Run the program:
cargo run --quiet
The final output should be:
Inspecting: Ari, Bo
Caller still owns: Ari, Bo
Before update: Ari, Bo
Updated: Ari, Bo, Mina
The mutable borrow ends when add_guest returns. The final print can read guest_list again, proving that ownership stayed in main while the function made a controlled update.
Summary
You used &String for shared, read-only access and &mut String for temporary, exclusive modification. In both cases the caller retained ownership, and the compiler helped enforce the difference between viewing and changing borrowed data.



