fn read(y: bool) { if y { println!("y is true!"); } } // Rust wants to ensure no undefined behavior at compile-time // Sounds a lot like Haskell! fn main() { // read(x); // Moving read here would cause an error let x = true; read(x); // ------------------------------------------------------------- // How variable live in the stack let n = 5; // step 1: stack stores n = 5 let y = plus_one(n); // step 3: stack stores n = 5 and y = 6 now println!("The value of y is: {y}"); // These variables live in frames // The frame for main at step 1 holds n = 5 // Frame for plus_one at step 2 holds x = 5 // Frame for main at step 3 holds n = 5 and y = 6 // // These frames get organized into a stack of currently-called-functions. // At step 2, the frame for main sits above the frame for the called function, plus_one. // // For Rust to transfer access to data without copying it, it uses pointers. // Pointers and pointees // Rust can put data on the heap with Box. // The stack holds data associated with specific functions while // the heap holds data that can outlive a function. // There is only one array in memory at a time with this method. let a = Box::new([0; 1_000_000]); let b = a; // println!("first value of a {}", a[0]); // This code is invalid bc of borrowing from a // Rust doesn't allow user memory management // ------------------------------------------------------------- // Box's owner manages deallocation // Almost how this works: // When a variable is bound to a box, when Rust deallocates the variable's // frame, then Rust deallocates the box's heap memory. let a_num = 4; make_and_drop(); // How this works fully (uses ownership): // When variable owns a box, when Rust deallocates the variable's frame, // then Rust deallocates the box's heap memory. let d = Box::new([0; 1_000_000]); // d owns this Box here let e = d; // e has ownership of the box transfered to it from d. Say it's moved // Rust data structures like String, Vec, and HashMap use Boxes. // Variables can't be used after moving // Can use .clone() to avoid moving data let first = String::from("Ferris"); let first_clone = first.clone(); let full = add_suffix(first_clone); println!("{full}, originally {first}"); } fn plus_one(x: i32) -> i32 { x + 1 // step 2: stack stores n = 5 from main and x = 5 in this function } fn make_and_drop() { let a_box = Box::new(5); } fn add_suffix(mut name: String) -> String { name.push_str(" Jr. "); name }