Mutable References
fn append(s: &mut String, extra: &str) {
s.push_str(extra);
}
fn main() {
let mut s = String::from("hello");
append(&mut s, ", world");
println!("{}", s); // "hello, world"
// Aliasing XOR Mutability rule:
let mut data = String::from("abc");
{
let r1 = &data; // immutable
let r2 = &data; // also fine
println!("{} {}", r1, r2);
// r1, r2 end here (NLL)
}
let r3 = &mut data; // Now mutable is fine
r3.push('d');
println!("{}", r3);
}
// Interior mutability with RefCell:
use std::cell::RefCell;
fn interior_mutability() {
let x = RefCell::new(vec![1, 2, 3]);
x.borrow_mut().push(4); // Runtime borrow check
println!("{:?}", x.borrow()); // [1, 2, 3, 4]
}Common Mutable Reference Patterns
fn sort_desc(v: &mut Vec) {
v.sort_by(|a, b| b.cmp(a));
}
fn capitalize(s: &mut String) {
if let Some(c) = s.get_mut(0..1) {
c.make_ascii_uppercase();
}
}
fn double_values(v: &mut Vec) {
for x in v.iter_mut() {
*x *= 2;
}
}
fn main() {
let mut nums = vec![3, 1, 4, 1, 5, 9, 2, 6];
sort_desc(&mut nums);
println!("{:?}", nums);
double_values(&mut nums);
println!("{:?}", nums);
} 🎯 Practice
- Write fn remove_duplicates(v: &mut Vec<i32>) that removes duplicates in-place
- Write fn normalize(v: &mut Vec<f64>) that scales values to [0.0, 1.0]
- Use RefCell to create a logger that can be "borrowed mutably" through an immutable reference
🎉 Key Takeaways
- &mut T allows modifying borrowed data - variable must be declared mut
- Only one &mut reference at a time, no mixing with &T references
- RefCell provides runtime borrow checking for interior mutability
- iter_mut() gives &mut T references for in-place modification