Rust Interview Questions
Rust
Web DevelopmentIoTQuestion 5
What is the difference between &mut
and &
in Rust?
Answer:
In Rust, &mut
and &
are used to create mutable and immutable references, respectively. These references allow you to borrow a value without taking ownership, but they come with different capabilities and restrictions.
Immutable References (&
)
- Syntax:
&T
whereT
is the type of the value being borrowed. - Usage: Allows you to read data without taking ownership or modifying the value.
- Multiple References: You can have multiple immutable references to the same value simultaneously.
- Safety: Ensures that the value cannot be modified while it is immutably borrowed, preventing data races.
- Example:
fn main() { let s = String::from("hello"); let r1 = &s; // Immutable reference let r2 = &s; // Another immutable reference println!("{} and {}", r1, r2); // Allowed because both are immutable references }
Mutable References (&mut
)
- Syntax:
&mut T
whereT
is the type of the value being borrowed. - Usage: Allows you to modify the value being borrowed.
- Single Reference: Only one mutable reference to a value is allowed at a time. This ensures that there are no simultaneous modifications that could lead to data races.
- Safety: Prevents other references (either mutable or immutable) to the same value while it is mutably borrowed.
- Example:
fn main() { let mut s = String::from("hello"); let r = &mut s; // Mutable reference r.push_str(", world"); // Allowed because r is a mutable reference println!("{}", r); }
Key Differences:
-
Mutability:
&
: Immutable reference; you can read the value but cannot modify it.&mut
: Mutable reference; you can modify the value.
-
Number of References:
&
: Multiple immutable references are allowed simultaneously.&mut
: Only one mutable reference is allowed at a time. While a mutable reference exists, no immutable references are allowed.
-
Use Cases:
&
: Use when you need to read data without modifying it.&mut
: Use when you need to modify the data.
-
Concurrency and Safety:
&
: Ensures that data cannot be modified, thus preventing data races.&mut
: Ensures that only one part of the code can modify the data at a time, also preventing data races.
Practical Example Illustrating Both:
fn main() {
let mut s = String::from("hello");
// Immutable borrow
let len = calculate_length(&s); // Borrowing s immutably
println!("The length of '{}' is {}", s, len); // s can still be used here
// Mutable borrow
change(&mut s); // Borrowing s mutably
println!("After change: {}", s); // s can be used again after the mutable borrow ends
}
fn calculate_length(s: &String) -> usize {
s.len() // Access the length without taking ownership
}
fn change(s: &mut String) {
s.push_str(", world"); // Mutate the String
}
In this example:
- The
calculate_length
function borrowss
immutably with&s
, allowing it to read the value without modifying it. - The
change
function borrowss
mutably with&mut s
, allowing it to modify the value. - After each borrow,
s
can still be used by the owner since the ownership was never transferred, only temporarily borrowed.