Rust Stack and Heap

In Rust, variables can be allocated on either the stack or the heap, depending on how they're declared.

The stack is a region of memory that is used to store variables that have a fixed size and lifetime. When you declare a variable on the stack, Rust automatically manages its lifetime for you, and the variable is automatically deallocated when it goes out of scope.

Here's an example of a variable allocated on the stack:

fn main() {
    let x = 5;  // variable x is allocated on the stack
    println!("x: {}", x);
}  // x is automatically deallocated when the function exits
Source:w‮w‬w.theitroad.com

In this example, we're declaring a variable x with a value of 5 inside the main function. Since x has a fixed size and lifetime, Rust allocates it on the stack. When the function exits, Rust automatically deallocates x, because its lifetime has ended.

The heap is a region of memory that is used to store variables that have a dynamic size or lifetime. When you allocate a variable on the heap, you're responsible for managing its lifetime and deallocating it when you're done with it.

Here's an example of a variable allocated on the heap:

fn main() {
    let mut s = String::from("hello");  // variable s is allocated on the heap
    s.push_str(", world!");  // modify the value of s

    println!("{}", s);  // prints "hello, world!"

    // s is automatically deallocated when it goes out of scope, but we can also deallocate it manually using the drop function:
    drop(s);  // deallocates the memory used by s
}

In this example, we're declaring a variable s using the String::from constructor, which allocates a string on the heap. We're then modifying the value of s by appending ", world!" to it using the push_str method. Finally, we're printing the value of s and manually deallocating it using the drop function.

It's important to note that Rust's ownership model ensures that heap-allocated variables are always properly managed and deallocated, which helps prevent common bugs like memory leaks and use-after-free errors. Rust's borrow checker enforces strict rules for ownership and borrowing, which help prevent data races and other concurrency bugs as well.