Rust Cheatsheet
Rust Cheatsheet
A quick-reference guide for essential and advanced Rust concepts, covering mutability, ownership, pattern matching, error handling, traits, smart pointers, and Cargo commands.
Variables & Mutability
fn main() {
let x = 5; // Immutable variable (default)
// x = 6; // Error: Cannot assign twice to immutable variable
let mut y = 5; // Mutable variable
y = 6; // Success
const MAX_POINTS: u32 = 100_000; // Constant (must have explicit type, resolved at compile-time)
// Shadowing (re-declaring variable with same name, can change type)
let spaces = " ";
let spaces = spaces.len(); // Shadowed 'spaces' is now an integer
}
Ownership & Borrowing
fn main() {
// 1. Move Semantics (Types on heap move ownership by default)
let s1 = String::from("hello");
let s2 = s1; // s1 is MOVED to s2. s1 is no longer valid.
// console.log!("{}", s1); // Error: Value borrowed here after move
// 2. References & Borrowing
let len = calculate_length(&s2); // Pass read-only reference (&s2)
// 3. Mutable References
let mut s3 = String::from("hello");
change_string(&mut s3); // Pass mutable reference (&mut s3)
// Borrowing Rules:
// - You can have any number of immutable references (&T) OR
// - Exactly ONE mutable reference (&mut T) at any given time
// - References must always be valid (no dangling references)
}
fn calculate_length(s: &String) -> usize {
s.len() // Returns size, does not take ownership
}
fn change_string(s: &mut String) {
s.push_str(", world"); // Modifies original String safely
}
Structs & Enums
// Standard Struct
struct User {
username: String,
email: String,
active: bool,
}
// Tuple Struct (Named fields are omitted)
struct Color(i32, i32, i32);
// Implementation block (defines methods)
impl User {
fn greet(&self) { // Method (takes &self reference)
println!("Hello, {}!", self.username);
}
fn create_new(username: String, email: String) -> Self { // Associated Function (static helper)
Self { username, email, active: true }
}
}
// Enums with data
enum Message {
Quit,
Move { x: i32, y: i32 }, // Anonymous struct data
Write(String), // Tuple data
ChangeColor(i32, i32, i32),
}
Pattern Matching
fn process_message(msg: Message) {
match msg {
Message::Quit => {
println!("Quitting");
}
Message::Move { x, y } => {
println!("Moving to x: {}, y: {}", x, y);
}
Message::Write(text) => {
println!("Text: {}", text);
}
_ => println!("Other action"), // Default match fallback
}
}
// if let (Destructure a single pattern cleanly)
fn check_optional(opt: Option<i32>) {
if let Some(number) = opt {
println!("Number is: {}", number);
}
}
Error Handling
// 1. Unrecoverable Errors (Crash the thread immediately)
// panic!("Fatal crash occurred!");
// 2. Recoverable Errors (Option & Result)
// Option<T>: Some(T) or None (Represents presence/absence of value)
let item: Option<i32> = Some(10);
let val = item.unwrap_or(0); // Safe unwrap with fallback default
// Result<T, E>: Ok(T) or Err(E) (Represents success or failure of operations)
fn read_username_from_file() -> Result<String, std::io::Error> {
let mut file = std::fs::File::open("username.txt")?; // '?' operator propagates error upward instantly
let mut username = String::new();
std::io::Read::read_to_string(&mut file, &mut username)?;
Ok(username)
}
Collections
// 1. Vectors (Dynamically sized arrays)
let mut v: Vec<i32> = Vec::new();
v.push(1);
v.push(2);
let third: &i32 = &v[1]; // Direct index borrow (panics if out of bounds)
let safe_third: Option<&i32> = v.get(1); // Safe retrieval (returns Some or None)
// 2. Strings vs String slices
let s1: &str = "Hello"; // String slice (fixed size, immutable reference)
let mut s2: String = s1.to_string(); // String (heap-allocated, dynamic, mutable)
s2.push_str(" World");
// 3. HashMaps
use std::collections::HashMap;
let mut scores = HashMap::new();
scores.insert(String::from("Blue"), 10);
let team_score = scores.get("Blue"); // Returns Option<&i32>
Traits & Generics
// Generics in Structs
struct Point<T> {
x: T,
y: T,
}
// Traits (Interface behavior agreements)
pub trait Summary {
fn summarize(&self) -> String;
// Default implementation
fn default_summary(&self) -> String {
String::from("(Read more...)")
}
}
// Implementing Traits
impl Summary for User {
fn summarize(&self) -> String {
format!("User: {}", self.username)
}
}
// Trait Bounds (Restrict generics to specific trait behaviors)
pub fn notify<T: Summary>(item: &T) {
println!("Notification: {}", item.summarize());
}
Smart Pointers
// Box<T> (Heap allocation: puts data on heap, keeps pointer on stack)
let b = Box::new(5);
// Rc<T> (Reference Counted: enables multiple read-only ownerships on single-threaded)
use std::rc::Rc;
let rc_data = Rc::new(String::from("shared"));
let ref1 = Rc::clone(&rc_data); // Increments reference count, does not copy string data
// Arc<T> (Atomically Reference Counted: safe thread-safe Rc alternative)
use std::sync::Arc;
let arc_data = Arc::new(String::from("thread-shared"));
Cargo Commands
cargo new <project_name> # Create a new binary Cargo package
cargo build # Compile the current package in Debug mode
cargo build --release # Compile package with optimizations in Release mode
cargo run # Compile and run the binary target
cargo test # Compile and run all unit and integration tests
cargo check # Fast check: analyze code for compile errors without writing binary
cargo clippy # Run linter tool to analyze styles and idiomatic warnings
cargo fmt # Format all files in active crate according to Rustfmt
cargo update # Check and update all local dependencies in Cargo.lock