Memory Safety in Rust


 

Rust’s ownership system eliminates entire classes of memory bugs while maintaining performance. Here’s how it works:

 

1. Ownership Rules

 

The foundation of Rust’s memory safety is built on three key ownership rules:

  • Each value has exactly one owner
  • When the owner goes out of scope, the value is dropped
  • Assignment transfers ownership (moves)

Here’s a simple example demonstrating ownership:

fn main() {
    let s1 = String::from("hello"); // s1 owns the string
    let s2 = s1;                    // Ownership moves to s2

    // println!("{}", s1);          // Error! Value was moved
    println!("{}", s2);             // This works
}

 

2. Borrowing (References)

 

Borrowing allows you to reference data without taking ownership:

  • Create read-only references with &
  • Multiple immutable borrows are allowed
  • References must always be valid
fn calculate_length(s: &String) -> usize {
    s.len()
}

fn main() {
    let s = String::from("hello");
    let len = calculate_length(&s);
    println!("Length: {}", len);
}

 

3. Mutable References

 

When you need to modify borrowed data:

  • Only one mutable reference is allowed at a time
  • No immutable borrows can exist simultaneously
  • Prevents data races at compile time

 

fn modify(s: &mut String) {
    s.push_str(", world!");
}

fn main() {
    let mut s = String::from("hello");
    modify(&mut s);
    println!("{}", s); // Prints "hello, world!"
}

 

Practical Example

 

Here’s a practical example that brings these concepts together:

 

fn process_text(text: &str) -> String {
    let mut result = String::new();
    result.push_str("Processed: ");
    result.push_str(text);
    result
}

fn main() {
    let input = String::from("Rust is awesome");
    let output = process_text(&input);
    println!("{}", output);
}