Rust Quick Reference
Everything you need day‑to‑day – syntax, ownership, and modern features.
Basic Syntax
fn main() {
println!("Hello, World!");
}
Variables & Mutability
// Immutable by default let x = 5; x = 6; // error // Mutable let mut y = 5; y = 6; // ok // Constants const PI: f64 = 3.14159; const STATUS_OK: u32 = 200; // Shadowing let x = 5; let x = x + 1; // new variable shadows old one // Type annotation let age: i32 = 25; let name: &str = "Alice";
Data Types
Scalar Types
i8, i16, i32, i64, i128– signedu8, u16, u32, u64, u128– unsignedf32, f64– floating pointbool– true / falsechar– Unicode characterisize, usize– pointer‑sized
Compound Types
tuple– (T1, T2, ...)array– [T; N]slice– &[T]struct– fieldsenum– variantsString– heap‑allocated&str– string sliceVec<T>– dynamic arrayHashMap<K, V>– key‑value
Type Conversion
let x = 42;
let y = x as f64; // cast
let s = String::from("123");
let n: i32 = s.parse().unwrap();
Control Flow
if / else
if x > 0 { println!("positive"); } else if x < 0 { println!("negative"); } else { println!("zero"); } // If as expression let result = if x > 0 { "positive" } else { "negative" };
match
match value {
1 => println!("one"),
2 => println!("two"),
3..=10 => println!("3-10"),
_ => println!("other"),
}
// Match with destructuring
match person {
Person { name, age: 25 } => println!("{} is 25", name),
Person { name, .. } => println!("{} is other age", name),
}
// Option match
match optional {
Some(value) => println!("got: {}", value),
None => println!("nothing"),
}
// Result match
match result {
Ok(val) => println!("success: {}", val),
Err(e) => println!("error: {}", e),
}
Loops
// loop (infinite) loop { println!("running..."); break; } // while while condition { println!("running..."); } // for (range) for i in 0..10 { println!("{}", i); } // for (inclusive) for i in 0..=10 { println!("{}", i); } // for over iterators for item in vec.iter() { println!("{}", item); } // continue / break for i in 0..10 { if i % 2 == 0 { continue; } if i > 7 { break; } println!("{}", i); }
Ownership & Borrowing
// Ownership rules let s1 = String::from("hello"); let s2 = s1; // s1 moved, cannot use // Clone (deep copy) let s1 = String::from("hello"); let s2 = s1.clone(); // Borrowing (references) let s = String::from("hello"); let len = calculate_length(&s); // borrow s (immutable) // Mutable reference let mut s = String::from("hello"); change(&mut s); // borrow mutably // Dangling references (prevented at compile time) { let r; { let x = 5; r = &x; // error: x doesn't live long enough } } // Slices let s = String::from("hello world"); let hello = &s[0..5]; let world = &s[6..11];
Structs
struct Person { name: String, age: u32, city: String, } // Create instance let person = Person { name: String::from("Alice"), age: 25, city: String::from("Delhi"), }; // Access fields println!("{}", person.name); // Tuple struct struct Point(i32, i32); let p = Point(10, 20); // Unit struct struct Unit; // Impl methods impl Person { fn greet(&self) -> String { format!("Hello, {}", self.name) } fn birthday(&mut self) { self.age += 1; } fn new(name: String, age: u32, city: String) -> Self { Self { name, age, city } } }
Enums
enum Status { Active, Inactive, Pending, } // Enum with data enum Result<T, E> { Ok(T), Err(E), } // Enum with different types enum Message { Quit, Move { x: i32, y: i32 }, Write(String), ChangeColor(u8, u8, u8), } // Use enum let status = Status::Active; let msg = Message::Write(String::from("hello")); // Option let x: Option<i32> = Some(5); let y: Option<i32> = None; // Result let success: Result<u32, &str> = Ok(200); let error: Result<u32, &str> = Err("failed");
Traits
// Define trait trait Greeter { fn greet(&self) -> String; fn farewell(&self) -> String { String::from("Goodbye") } } // Implement trait impl Greeter for Person { fn greet(&self) -> String { format!("Hello, {}!", self.name) } } // Trait as parameter fn say_hello(item: &impl Greeter) { println!("{}", item.greet()); } // Trait bound syntax fn say_hello<T: Greeter>(item: &T) { println!("{}", item.greet()); } // Derive traits #[derive(Debug, Clone, PartialEq)] struct User { name: String, age: u32, }
Error Handling
// Result type use std::fs::File; use std::io::ErrorKind; fn open_file() { let file_result = File::open("file.txt"); let file = match file_result { Ok(file) => file, Err(e) => match e.kind() { ErrorKind::NotFound => File::create("file.txt").unwrap(), other => panic!("Error: {:?}", other), }, }; } // Unwrap / expect let file = File::open("file.txt").unwrap(); let file = File::open("file.txt").expect("Failed to open file"); // ? operator (propagate error) fn read_file() -> Result<String, std::io::Error> { let mut s = String::new(); File::open("file.txt")?.read_to_string(&mut s)?; Ok(s) } // Custom error type use std::fmt; #[derive(Debug)] struct MyError { code: u32, message: String, } impl fmt::Display for MyError { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "error {}: {}", self.code, self.message) } } impl std::error::Error for MyError {} // Panic panic!("something went wrong");
Concurrency
use std::thread;
use std::time::Duration;
use std::sync::mpsc;
use std::sync::{Arc, Mutex};
// Spawn thread
let handle = thread::spawn(|| {
for i in 0..5 {
println!("thread: {}", i);
thread::sleep(Duration::from_millis(100));
}
});
handle.join().unwrap();
// Move data to thread
let data = vec![1, 2, 3];
let handle = thread::spawn(move || {
println!("data: {:?}", data);
});
// Channel (mpsc)
let (tx, rx) = mpsc::channel();
thread::spawn(move || {
tx.send("Hello").unwrap();
});
let received = rx.recv().unwrap();
// 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);
}
for handle in handles {
handle.join().unwrap();
}
println!("Result: {}", *counter.lock().unwrap());
Collections
Vec
let mut v = vec![1, 2, 3]; v.push(4); v.pop(); // Iterate for i in &v { println!("{}", i); } // Get let first = v.get(0); // Option let first = &v[0]; // panics if out of bounds
HashMap
use std::collections::HashMap;
let mut map = HashMap::new();
map.insert("Alice", 25);
map.insert("Bob", 30);
// Get
let age = map.get("Alice"); // Option
// Iterate
for (key, value) in &map {
println!("{}: {}", key, value);
}
// Entry API
map.entry("Charlie").or_insert(35);
Modules & Crates
// module.rs mod utils; // Nested module mod math { pub fn add(a: i32, b: i32) -> i32 { a + b } } // Use use utils::helper; use math::add; // Re‑export pub use math::add; // External crate use serde::{Serialize, Deserialize}; // Cargo.toml dependencies [dependencies] serde = "1.0" rand = "0.8"
Common Standard Library
String
len()is_empty()push_str(s)push(c)contains(s)replace(old, new)split(sep)trim()to_uppercase()to_lowercase()
Iterator
iter()– immutableiter_mut()– mutableinto_iter()– consumesmap(f)filter(f)fold(acc, f)collect()enumerate()zip(other)take(n)skip(n)
Testing
// test module #[cfg(test)] mod tests { #[test] fn test_add() { assert_eq!(add(2, 3), 5); } #[test] fn test_add_fail() { assert_ne!(add(2, 3), 4); } #[test] #[should_panic(expected = "division by zero")] fn test_division_panic() { divide(1, 0); } } // Run tests // cargo test
Best Practices
- Use
cargo fmtto format code. - Use
cargo clippyfor linting. - Prefer
Resultoverunwrap()in production code. - Use
derivefor common traits (Debug, Clone, PartialEq). - Use
letfor immutable by default – onlymutwhen needed. - Use
&strfor parameters that accept string slices. - Use
Vec<T>over arrays for dynamic collections. - Use
Optionfor nullable values instead ofnull. - Use
Resultfor operations that can fail. - Use
matchfor exhaustive pattern matching. - Use
cargofor building, testing, and dependencies. - Follow the
Rustproject structure –src/,tests/,examples/.
📌 Quick Reference
Check Rust version:
Create new project:
Build project:
Run project:
Run tests:
Format code:
Lint code:
rustc --versionCreate new project:
cargo new projectBuild project:
cargo buildRun project:
cargo runRun tests:
cargo testFormat code:
cargo fmtLint code:
cargo clippy