Rust: Safe Systems Programming

Learn Rust, the language that guarantees memory safety without a garbage collector


Rust: Safe Systems Programming
1 Loading...

Rust: Safe Systems Programming

Rust is a systems programming language that combines low-level performance with compile-time safety guarantees. Created by Mozilla and released in 2010, Rust eliminates entire classes of memory-related bugs through its unique ownership system, without sacrificing performance.

Why Rust? Rust has been voted the “most loved language” in the Stack Overflow Survey for 8 consecutive years. Companies like Microsoft, Google, Amazon, and Discord use Rust in production.

Fundamental Concepts

Ownership, Borrowing, and Lifetimes

The ownership system is the heart of Rust:

// Ownership - each value has a single owner
fn main() {
    let s1 = String::from("hello");
    let s2 = s1; // s1 is moved to s2
    // println!("{}", s1); // ERROR! s1 is no longer valid
    println!("{}", s2); // OK
}

// Borrowing - immutable references
fn calculate_length(s: &String) -> usize {
    s.len()
}

// Mutable borrowing
fn add_text(s: &mut String) {
    s.push_str(" world");
}

fn main() {
    let mut text = String::from("hello");
    
    // Multiple immutable references are allowed
    let r1 = &text;
    let r2 = &text;
    println!("{} and {}", r1, r2);
    
    // Only ONE mutable reference at a time
    let r3 = &mut text;
    r3.push_str("!");
    println!("{}", r3);
}

// Lifetimes - ensure references are valid
fn longest<'a>(x: &'a str, y: &'a str) -> &'a str {
    if x.len() > y.len() { x } else { y }
}

Data Types

// Primitive types
let integer: i32 = 42;
let floating: f64 = 3.14;
let boolean: bool = true;
let character: char = '🦀';

// Tuples
let tuple: (i32, f64, &str) = (42, 3.14, "rust");
let (x, y, z) = tuple; // Destructuring

// Arrays (fixed size)
let array: [i32; 5] = [1, 2, 3, 4, 5];
let first = array[0];

// Vectors (dynamic size)
let mut vec: Vec<i32> = vec![1, 2, 3];
vec.push(4);

// Strings
let s1: &str = "string literal"; // String slice
let s2: String = String::from("owned string");

// HashMap
use std::collections::HashMap;
let mut map: HashMap<&str, i32> = HashMap::new();
map.insert("key", 42);

Structs and Enums

// Struct
#[derive(Debug, Clone)]
struct User {
    name: String,
    email: String,
    age: u32,
    active: bool,
}

impl User {
    // Constructor
    fn new(name: String, email: String, age: u32) -> Self {
        Self {
            name,
            email,
            age,
            active: true,
        }
    }
    
    // Method
    fn greet(&self) -> String {
        format!("Hello, {}!", self.name)
    }
    
    // Mutable method
    fn deactivate(&mut self) {
        self.active = false;
    }
}

// Enum with data
enum Message {
    Quit,
    Move { x: i32, y: i32 },
    Write(String),
    ChangeColor(u8, u8, u8),
}

// Pattern matching
fn process_message(msg: Message) {
    match msg {
        Message::Quit => println!("Quitting..."),
        Message::Move { x, y } => println!("Moving to ({}, {})", x, y),
        Message::Write(text) => println!("Text: {}", text),
        Message::ChangeColor(r, g, b) => println!("Color: RGB({}, {}, {})", r, g, b),
    }
}

// Option and Result
fn divide(a: f64, b: f64) -> Option<f64> {
    if b == 0.0 { None } else { Some(a / b) }
}

fn read_file(path: &str) -> Result<String, std::io::Error> {
    std::fs::read_to_string(path)
}

Traits

// Defining a trait
trait Summarizable {
    fn summarize(&self) -> String;
    
    // Default implementation
    fn description(&self) -> String {
        format!("Summary: {}", self.summarize())
    }
}

// Implementing trait
struct Article {
    title: String,
    author: String,
    content: String,
}

impl Summarizable for Article {
    fn summarize(&self) -> String {
        format!("{} by {}", self.title, self.author)
    }
}

// Trait bounds in generics
fn print_summary<T: Summarizable>(item: &T) {
    println!("{}", item.summarize());
}

// Multiple trait bounds
fn process<T: Summarizable + Clone + std::fmt::Debug>(item: T) {
    println!("{:?}", item);
}

// Where clause for readability
fn complex_function<T, U>(t: T, u: U) -> String
where
    T: Summarizable + Clone,
    U: std::fmt::Display,
{
    format!("{}: {}", t.summarize(), u)
}

Error Handling

use std::fs::File;
use std::io::{self, Read};

// Error propagation with ?
fn read_user() -> Result<String, io::Error> {
    let mut file = File::open("user.txt")?;
    let mut content = String::new();
    file.read_to_string(&mut content)?;
    Ok(content)
}

// Custom error
#[derive(Debug)]
enum MyError {
    Io(io::Error),
    Parse(std::num::ParseIntError),
    Custom(String),
}

impl From<io::Error> for MyError {
    fn from(err: io::Error) -> Self {
        MyError::Io(err)
    }
}

Concurrency

use std::thread;
use std::sync::{Arc, Mutex};

// Basic threads
fn main() {
    let handle = thread::spawn(|| {
        for i in 1..10 {
            println!("Thread: {}", i);
        }
    });
    
    for i in 1..5 {
        println!("Main: {}", i);
    }
    
    handle.join().unwrap();
}

// Sharing data between threads
fn shared_counter() {
    let counter = Arc::new(Mutex::new(0));
    let mut handles = vec![];
    
    for _ in 0..10 {
        let counter = Arc::clone(&counter);
        let handle = thread::spawn(move || {
            let mut num = counter.lock().unwrap();
            *num += 1;
        });
        handles.push(handle);
    }
    
    for handle in handles {
        handle.join().unwrap();
    }
    
    println!("Result: {}", *counter.lock().unwrap());
}

Ecosystem Tools

ToolPurpose
cargoPackage manager and build tool
rustfmtCode formatter
clippyLinter with advanced tips
rust-analyzerLSP for IDEs

Learning Checklist

  • Understand ownership, borrowing, and lifetimes
  • Master structs, enums, and pattern matching
  • Learn traits and generics
  • Study error handling with Result and Option
  • Explore concurrency and async/await
  • Build a CLI project
  • Contribute to Rust open source projects

Essential Resources

Quote

“Rust is a language that respects the developer’s time and intelligence.” - Steve Klabnik


Rust may seem challenging at first, but the safety guarantees it offers are worth the investment!