Ownership, borrowing, lifetimes, traits, enums, pattern matching, error handling & concurrency
Language// Variables (immutable by default!)
let x = 5; // immutable
let mut y = 10; // mutable
const MAX: u32 = 100; // compile-time constant
// Scalar types
let a: i32 = 42; // signed integers: i8, i16, i32, i64, i128
let b: u64 = 100; // unsigned: u8, u16, u32, u64, u128
let c: f64 = 3.14; // floats: f32, f64
let d: bool = true;
let e: char = 'π¦'; // 4 bytes, Unicode
// Compound types
let tup: (i32, f64, char) = (42, 3.14, 'x'); // tuple
let (x, y, z) = tup; // destructure
let arr: [i32; 5] = [1, 2, 3, 4, 5]; // fixed-size array
// String types
let s1: &str = "hello"; // string slice (borrowed, stack)
let s2: String = String::from("hello"); // owned String (heap)
let s3 = format!("{} {}", s1, s2);
// Functions
fn add(a: i32, b: i32) -> i32 {
a + b // no semicolon = return expression
}Rust's core innovation β memory safety without garbage collection.
// Move (ownership transfer)
let s1 = String::from("hello");
let s2 = s1; // s1 is MOVED to s2, s1 is now invalid
// println!("{}", s1); // β compile error!
// Clone (deep copy)
let s1 = String::from("hello");
let s2 = s1.clone(); // s1 still valid
// Borrowing (references)
fn len(s: &String) -> usize { // immutable borrow
s.len()
}
fn push_hello(s: &mut String) { // mutable borrow
s.push_str(", hello");
}
// Rules:
// - Any number of &T (immutable refs) OR
// - Exactly one &mut T (mutable ref)
// - Never both at the same time
// Lifetimes (explicit when needed)
fn longest<'a>(x: &'a str, y: &'a str) -> &'a str {
if x.len() > y.len() { x } else { y }
}// Struct
struct User {
name: String,
age: u32,
active: bool,
}
impl User {
// Associated function (constructor)
fn new(name: &str, age: u32) -> Self {
User { name: name.to_string(), age, active: true }
}
// Method (takes &self)
fn greet(&self) -> String {
format!("Hi, I'm {} ({})", self.name, self.age)
}
}
let u = User::new("Alice", 30);
// Enum (algebraic data types)
enum Shape {
Circle(f64), // radius
Rectangle(f64, f64), // width, height
Triangle { base: f64, height: f64 },
}
// Option<T> β Rust's null alternative
let x: Option<i32> = Some(42);
let y: Option<i32> = None;
let val = x.unwrap_or(0); // safe default// match (exhaustive!)
match shape {
Shape::Circle(r) => std::f64::consts::PI * r * r,
Shape::Rectangle(w, h) => w * h,
Shape::Triangle { base, height } => 0.5 * base * height,
}
// if let (single pattern)
if let Some(val) = optional_value {
println!("Got: {}", val);
}
// while let
while let Some(item) = stack.pop() {
println!("{}", item);
}
// Destructuring in match
match (x, y) {
(0, 0) => "origin",
(x, 0) => "x-axis",
(0, y) => "y-axis",
(x, y) if x == y => "diagonal", // match guard
_ => "other", // catch-all
}// Define a trait (like an interface)
trait Summary {
fn summarize(&self) -> String;
fn default_method(&self) -> String {
String::from("(Read more...)")
}
}
// Implement for a type
impl Summary for User {
fn summarize(&self) -> String {
format!("{} ({})", self.name, self.age)
}
}
// Trait bounds (generics)
fn notify(item: &impl Summary) { ... }
fn notify<T: Summary + Display>(item: &T) { ... }
// Common derive traits
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
struct Point { x: f64, y: f64 }// Result<T, E> β recoverable errors
fn read_file(path: &str) -> Result<String, std::io::Error> {
std::fs::read_to_string(path)
}
// Handle with match
match read_file("data.txt") {
Ok(content) => println!("{}", content),
Err(e) => eprintln!("Error: {}", e),
}
// ? operator (propagate errors)
fn process() -> Result<(), Box<dyn std::error::Error>> {
let content = std::fs::read_to_string("file.txt")?; // returns Err if fails
let num: i32 = content.trim().parse()?;
Ok(())
}
// Unwrap helpers
let val = result.unwrap(); // panic if Err
let val = result.expect("msg"); // panic with message
let val = result.unwrap_or(0); // default value
let val = result.unwrap_or_else(|e| handle(e));// Vec<T> β growable array
let mut v: Vec<i32> = vec![1, 2, 3];
v.push(4); v.pop();
v.len(); v.is_empty();
v[0]; v.get(0); // Option<&T>
v.contains(&3); v.sort();
v.iter().for_each(|x| println!("{}", x));
// HashMap<K, V>
use std::collections::HashMap;
let mut map = HashMap::new();
map.insert("alice", 100);
map.entry("bob").or_insert(0);
if let Some(val) = map.get("alice") { ... }
// HashSet<T>
use std::collections::HashSet;
let set: HashSet<i32> = [1,2,3].iter().cloned().collect();
set.contains(&2);
set.intersection(&other_set);let nums = vec![1, 2, 3, 4, 5];
// Iterator chain
let result: Vec<i32> = nums.iter()
.filter(|&&x| x > 2)
.map(|&x| x * 10)
.collect(); // [30, 40, 50]
nums.iter().sum::<i32>(); // 15
nums.iter().any(|&x| x > 4); // true
nums.iter().all(|&x| x > 0); // true
nums.iter().find(|&&x| x > 3); // Some(&4)
nums.iter().enumerate(); // (index, value) pairs
nums.iter().zip(other.iter()); // pair up two iterators
nums.chunks(2); // [[1,2],[3,4],[5]]
// Closures
let add = |a: i32, b: i32| -> i32 { a + b };
let square = |x| x * x; // type inferenceuse std::thread;
use std::sync::{Arc, Mutex};
// Spawn thread
let handle = thread::spawn(|| {
println!("from thread!");
});
handle.join().unwrap();
// Shared state with Arc + Mutex
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);
}
// Channels (message passing)
use std::sync::mpsc;
let (tx, rx) = mpsc::channel();
thread::spawn(move || { tx.send("hello").unwrap(); });
let msg = rx.recv().unwrap();
// Async/await (with tokio)
// #[tokio::main]
// async fn main() {
// let result = fetch_data().await?;
// }# Create project
cargo new myapp
cargo new mylib --lib
# Build & run
cargo build # debug build
cargo build --release # optimized build
cargo run # build + run
cargo test # run tests
cargo fmt # format code
cargo clippy # linter
# Cargo.toml dependencies
[dependencies]
serde = { version = "1.0", features = ["derive"] }
tokio = { version = "1", features = ["full"] }
reqwest = "0.12"
axum = "0.7"
# Popular crates
# serde / serde_json β serialization
# tokio β async runtime
# axum β web framework
# sqlx β async SQL
# clap β CLI argument parsing
# anyhow / thiserror β error handling