fn print_box_content(b: Box) { println!("Box contains: {}", *b); // When b goes out of scope, the i32 value on the heap is deallocated. } // b and its owned data are dropped here. fn main() { // Storing data on the stack (default behavior) let x = 5; let y = x; // x is copied to y println!("x: {}, y: {}", x, y); // Storing data on the heap using Box let b1 = Box::new(5); println!("b1 (initially owned): {}", *b1); let b_moved = b1; // `b1` is moved into `b_moved` println!("b_moved (new owner): {}", *b_moved); // println!("b1 (after move): {}", *b1); // This would cause a compile-time error: value used after move let b_original = Box::new(10); print_box_content(b_original); // Ownership of b_original moves into the function. // println!("Original box: {}", *b_original); // This would be a compile error (value used after move). let mut b_mutable = Box::new(20); *b_mutable += 5; // Mutate the value inside the Box. println!("Mutable box: {}", *b_mutable); // Box is often used for recursive types where size isn't known at compile time, // like linked lists or binary trees. enum List { Cons(i32, Box), Nil, } use List::{Cons, Nil}; let list = Cons(1, Box::new(Cons(2, Box::new(Cons(3, Box::new(Nil)))))); // The Box here allows the List enum to have a known size at compile time, // even though the list can be arbitrarily long. }