Rust is a systems programming language focused on safety, speed, and concurrency. It prevents memory bugs at compile time without a garbage collector, making it ideal for performance-critical applications.
Why Rust?
- Memory safety — No null pointers, no dangling references, no data races
- Zero-cost abstractions — High-level features with no runtime cost
- Performance — Comparable to C/C++
- Concurrency — Fearless concurrency through the type system
- Modern tooling — Cargo (package manager), rustfmt, clippy
- Growing fast — Linux kernel, Android, Windows, Firefox, Deno all use Rust
Ownership System
Rust's key innovation: every value has exactly one owner.
Rust
fn main() {
let s1 = String::from("hello"); // s1 owns the String
let s2 = s1; // Ownership moves to s2
// println!("{}", s1); // ERROR: s1 is no longer valid!
let s3 = s2.clone(); // Deep copy (explicit)
println!("{} {}", s2, s3); // Both valid
// Borrowing (references)
let s4 = String::from("world");
let len = calculate_length(&s4); // Borrow immutably
println!("{} has length {}", s4, len); // s4 still valid
let mut s5 = String::from("hello");
change(&mut s5); // Borrow mutably
println!("{}", s5); // "hello, world"
}
fn calculate_length(s: &String) -> usize {
s.len()
}
fn change(s: &mut String) {
s.push_str(", world");
}Rules of Ownership
Rust
// Rule 1: Each value has one owner
let x = String::from("hello");
// Rule 2: When owner goes out of scope, value is dropped
{
let y = String::from("inner");
} // y is dropped here (memory freed)
// Rule 3: Ownership can be moved or borrowed
let s1 = String::from("hello");
let s2 = s1; // Moved (s1 invalidated)
let s3 = &s2; // Borrowed (s2 still valid)
// Borrowing rules:
// - Any number of immutable references: &T
// - OR exactly one mutable reference: &mut T
// - References must always be valid (no dangling)Basic Syntax
Rust
// Variables (immutable by default)
let x = 5;
let mut y = 10; // Mutable
y += 5;
// Constants
const MAX_POINTS: u32 = 100_000;
// Types
let name: &str = "Alice"; // String slice
let age: i32 = 28; // Signed 32-bit integer
let pi: f64 = 3.14159; // 64-bit float
let active: bool = true;
// Functions
fn add(a: i32, b: i32) -> i32 {
a + b // No semicolon = return expression
}
// If expression
let grade = if score >= 90 { "A" } else if score >= 80 { "B" } else { "F" };
// Pattern matching
match command {
"start" => println!("Starting..."),
"stop" => println!("Stopping..."),
_ => println!("Unknown command"),
}
// Vectors
let mut nums = vec![1, 2, 3, 4, 5];
nums.push(6);
for n in &nums {
println!("{}", n);
}
// HashMap
use std::collections::HashMap;
let mut scores = HashMap::new();
scores.insert("Alice", 95);
scores.insert("Bob", 87);Error Handling
Rust
use std::fs;
use std::io;
// Result type (no exceptions in Rust!)
fn read_file(path: &str) -> Result<String, io::Error> {
fs::read_to_string(path)
}
// Pattern matching
match read_file("config.txt") {
Ok(contents) => println!("File: {}", contents),
Err(e) => println!("Error: {}", e),
}
// ? operator (propagate errors)
fn process_config(path: &str) -> Result<Config, Box<dyn std::error::Error>> {
let contents = fs::read_to_string(path)?; // Returns Err if failed
let config: Config = serde_json::from_str(&contents)?;
Ok(config)
}
// Unwrap (use only in tests/prototypes)
let contents = fs::read_to_string("config.txt").unwrap(); // Panics on errorStructs and Enums
Rust
// Struct
struct User {
name: String,
email: String,
age: u32,
active: bool,
}
impl User {
fn new(name: String, email: String) -> Self {
User { name, email, age: 0, active: true }
}
fn greet(&self) -> String {
format!("Hi, I'm {}!", self.name)
}
}
// Tuple struct
struct Color(u8, u8, u8);
let red = Color(255, 0, 0);
// Enum
enum Shape {
Circle(f64), // radius
Rectangle(f64, f64), // width, height
Triangle(f64, f64, f64), // sides
}
fn area(shape: &Shape) -> f64 {
match shape {
Shape::Circle(r) => std::f64::consts::PI * r * r,
Shape::Rectangle(w, h) => w * h,
Shape::Triangle(a, b, c) => {
let s = (a + b + c) / 2.0;
(s * (s - a) * (s - b) * (s - c)).sqrt()
}
}
}💡 Tip: The borrow checker feels restrictive at first, but it's catching bugs that would crash C/C++ programs. Trust the compiler — once it compiles, whole classes of bugs are impossible.
Next: Ownership and Borrowing