79 lines
2.6 KiB
Rust

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
}