// Example 104: Mutable References (&mut T)
//
// Only ONE &mut T at a time. No &T while &mut T exists.
// This prevents data races at compile time.
// Approach 1: Mutable reference to a struct
struct Counter {
count: i32,
}
fn increment(c: &mut Counter) {
c.count += 1;
}
fn get_count(c: &Counter) -> i32 {
c.count
}
fn approach1() {
let mut c = Counter { count: 0 };
increment(&mut c);
increment(&mut c);
increment(&mut c);
assert_eq!(get_count(&c), 3);
println!("Counter: {}", get_count(&c));
}
// Approach 2: Mutable reference for accumulation
fn sum_into(data: &[i32], total: &mut i32) {
for &x in data {
*total += x;
}
}
fn approach2() {
let mut total = 0;
sum_into(&[1, 2, 3, 4, 5], &mut total);
assert_eq!(total, 15);
println!("Total: {}", total);
}
// Approach 3: In-place mutation of slices
fn reverse_in_place(arr: &mut [i32]) {
let n = arr.len();
for i in 0..n / 2 {
arr.swap(i, n - 1 - i);
}
}
fn approach3() {
let mut arr = vec![1, 2, 3, 4, 5];
reverse_in_place(&mut arr);
assert_eq!(arr, vec![5, 4, 3, 2, 1]);
println!("Reversed: {:?}", arr);
}
fn main() {
println!("=== Approach 1: Mutable Struct Reference ===");
approach1();
println!("\n=== Approach 2: Accumulation ===");
approach2();
println!("\n=== Approach 3: In-Place Mutation ===");
approach3();
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_increment() {
let mut c = Counter { count: 0 };
increment(&mut c);
assert_eq!(c.count, 1);
}
#[test]
fn test_exclusive_access() {
let mut val = 10;
let r = &mut val;
*r += 5;
// Can't create another &mut or & while r exists
assert_eq!(*r, 15);
}
#[test]
fn test_sum_into() {
let mut total = 0;
sum_into(&[10, 20, 30], &mut total);
assert_eq!(total, 60);
}
#[test]
fn test_reverse() {
let mut v = vec![1, 2, 3];
reverse_in_place(&mut v);
assert_eq!(v, vec![3, 2, 1]);
}
#[test]
fn test_mut_ref_reborrow() {
let mut data = vec![1, 2, 3];
{
let r = &mut data;
r.push(4);
} // r dropped here
// Now we can borrow again
assert_eq!(data.len(), 4);
}
}
(* Example 104: Mutable References โ OCaml Mutable Fields โ Rust &mut *)
(* Approach 1: Mutable record fields *)
type counter = { mutable count : int }
let increment c = c.count <- c.count + 1
let get_count c = c.count
let approach1 () =
let c = { count = 0 } in
increment c;
increment c;
increment c;
assert (get_count c = 3);
Printf.printf "Counter: %d\n" (get_count c)
(* Approach 2: Ref cells โ mutable references *)
let approach2 () =
let total = ref 0 in
List.iter (fun x -> total := !total + x) [1; 2; 3; 4; 5];
assert (!total = 15);
Printf.printf "Total: %d\n" !total
(* Approach 3: Mutable arrays *)
let reverse_in_place arr =
let n = Array.length arr in
for i = 0 to n / 2 - 1 do
let tmp = arr.(i) in
arr.(i) <- arr.(n - 1 - i);
arr.(n - 1 - i) <- tmp
done
let approach3 () =
let arr = [| 1; 2; 3; 4; 5 |] in
reverse_in_place arr;
assert (arr = [| 5; 4; 3; 2; 1 |]);
Printf.printf "Reversed: %s\n"
(String.concat ", " (Array.to_list (Array.map string_of_int arr)))
let () =
approach1 ();
approach2 ();
approach3 ();
Printf.printf "โ All tests passed\n"