Language Semantics
Memory Safety
Rust ensures memory safety at compile-time through its ownership model. This guarantees that no use-after-free or dangling pointers exist in valid Rust programs.
fn main() { let s1 = String::from("hello"); let s2 = s1; // Move // println!("{}", s1); // Compile error: variable moved println!("{}", s2); // Compilation OK }
Ownership and Borrowing
Ownership determines how Rust manages memory. Each value has a variable that's called its owner. There can only be one owner at a time.
- Ownership is transferred when values are assigned
- Borrowing allows referencing values without taking ownership
- References must be either
&
(immut) or&mut
(mut)
fn main() { let s = String::from("hello"); let p = &s; // immutable borrow let p_mut = &mut s; // mutable borrow }
Lifetimes
Lifences ensure references are valid. The compiler uses this information to prevent dangling references and use-after-free errors.
fn longest<'a>(s1: &'a str, s2: &'a str) -> &'a str { if s1.len() > s2.len() { s1 } else { s2 } }
The 'a
lifetime parameter indicates that all references returned will be valid as long as the references passed in are valid
Borrow Checker
The borrow checker ensures that memory is used safely. It enforces the following rules:
- Any number of immutable borrows
- Or one mutable borrow
- References are only valid for the scope they're in
fn main() { let mut s = String::from("hello"); let r1 = &s; // no problem let r2 = &s; // no problem // let r3 = &mut s; // compiler error! println!("{} and {}", r1, r2); }
Error Propagation
Rust provides explicit error handling with Result
and Option
types to ensure errors are properly handled:
enum Result<T, E> { Ok(T), Err(E), } enum Option<T> { Some(T), None, }
Functions use Result
to return either success or detailed error information:
fn divide(a: f64, b: f64) -> Result<f64, String> { if b == 0.0 { return Err("division by zero".to_string()); } Ok(a / b) }
Concurrency Semantics
Rust provides safe concurrency through a combination of threads and safe API:
- Memory safety across threads
- No need for locks in many cases
- Cross-thread communication via channels
use std::thread; fn main() { thread::spawn(|| { println!("Hello from a thread!"); }).join().unwrap(); }