RustRust Cheat Sheet

Rust Cheat Sheet

A quick reference for common Rust syntax and patterns. Each section shows compact, correct examples you can copy and adapt. For deeper explanations follow the links in the sidebar.

1. Variables

RUST
// Immutable binding (default)
let x = 5;

// Mutable binding
let mut y = 5;
y += 1;

// Shadowing — rebind with the same name
let x = x + 1;        // x is now 6
let x = x * 2;        // x is now 12

// Compile-time constant (type required, SCREAMING_SNAKE_CASE)
const MAX_POINTS: u32 = 100_000;

// Static — lives for the entire program
static LOG_LEVEL: &str = "info";
2. Data Types

Category

Types

Notes

Signed integers

i8, i16, i32, i64, i128, isize

Default integer is i32

Unsigned integers

u8, u16, u32, u64, u128, usize

usize matches pointer width

Floating point

f32, f64

Default float is f64

Boolean

bool

true or false

Character

char

Unicode scalar value, 4 bytes, single quotes

Tuple

(i32, f64, bool)

Fixed length, mixed types, access with .0 .1 …

Array

[i32; 5]

Fixed length, same type, stack-allocated

RUST
let t: (i32, f64, bool) = (500, 6.4, true);
let (a, b, c) = t;           // destructure
println!("{}", t.1);         // 6.4

let arr: [i32; 5] = [1, 2, 3, 4, 5];
let first = arr[0];
let slice = &arr[1..3];      // &[2, 3]
3. Strings

String

&str

Owned?

Yes

No (borrowed view)

Mutable?

Yes (if mut)

No

Stored on

Heap

Stack / data segment

Common use

Build / own text

Read-only string data

RUST
// Creating a String
let s1 = String::from("hello");
let s2 = "world".to_string();
let s3 = format!("{} {}", s1, s2);   // "hello world"

// String slices
let hello: &str = &s1[0..5];

// Key methods
let len  = s1.len();
let empty = s1.is_empty();
let upper = s1.to_uppercase();
let contains = s1.contains("ell");
let replaced = s1.replace("hello", "hi");
let trimmed  = "  hi  ".trim();

// Appending
let mut s = String::from("foo");
s.push(' ');          // single char
s.push_str("bar");    // string slice
4. Control Flow

RUST
// if/else as an expression
let number = 7;
let description = if number % 2 == 0 { "even" } else { "odd" };

// loop with a break value
let mut counter = 0;
let result = loop {
    counter += 1;
    if counter == 10 { break counter * 2; }
};                     // result == 20

// while
let mut n = 3;
while n != 0 { println!("{}", n); n -= 1; }

// for over a range
for i in 1..=5 { print!("{} ", i); }    // 1 2 3 4 5

// for over a collection
let v = vec![10, 20, 30];
for val in &v { println!("{}", val); }

// enumerate
for (i, val) in v.iter().enumerate() {
    println!("{}: {}", i, val);
}
5. Functions

RUST
// Named function — last expression is the implicit return value
fn add(x: i32, y: i32) -> i32 {
    x + y          // no semicolon = returned
}

// Explicit return (for early exit)
fn divide(a: f64, b: f64) -> Option<f64> {
    if b == 0.0 { return None; }
    Some(a / b)
}

// Closures
let double  = |x: i32| x * 2;
let greet   = |name: &str| format!("Hello, {}!", name);
let add_n   = |n: i32| move |x: i32| x + n;  // closure returning closure

fn apply(f: impl Fn(i32) -> i32, x: i32) -> i32 { f(x) }
println!("{}", apply(double, 5));   // 10
6. Ownership Rules
  1. Each value in Rust has a single owner.

  2. There can only be one owner at a time.

  3. When the owner goes out of scope, the value is dropped (memory freed).

RUST
let s1 = String::from("hello");
let s2 = s1;          // s1 is MOVED — s1 is no longer valid
// println!("{}", s1) // compile error

let s3 = s2.clone();  // deep copy — both s2 and s3 are valid
println!("{} {}", s2, s3);
7. References & Borrowing
  1. At any given time you can have either one mutable reference or any number of immutable references — but not both.

  2. References must always be valid (no dangling references).

RUST
fn length(s: &String) -> usize {  // immutable borrow
    s.len()
}

fn append(s: &mut String) {       // mutable borrow
    s.push_str(", world");
}

fn main() {
    let s = String::from("hello");
    println!("{}", length(&s));   // borrow — s still owned here

    let mut t = String::from("hello");
    append(&mut t);
    println!("{}", t);            // "hello, world"
}
8. Structs

RUST
// Named struct
struct Point { x: f64, y: f64 }

// Tuple struct
struct Color(u8, u8, u8);

// Unit struct (no fields)
struct Marker;

// impl block — methods take &self / &mut self / self
impl Point {
    // Associated function (no self) — called with Point::new(…)
    fn new(x: f64, y: f64) -> Self { Point { x, y } }

    // Method — called with p.distance_from_origin()
    fn distance_from_origin(&self) -> f64 {
        (self.x * self.x + self.y * self.y).sqrt()
    }
}

fn main() {
    let p = Point::new(3.0, 4.0);
    println!("{}", p.distance_from_origin()); // 5

    let red = Color(255, 0, 0);
    println!("r={}", red.0);
}
9. Enums

RUST
// Basic enum
enum Direction { North, South, East, West }

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

// Option<T> (in std — no import needed)
let some_number: Option<i32> = Some(5);
let no_number:   Option<i32> = None;

// Result<T, E>
fn parse(s: &str) -> Result<i32, std::num::ParseIntError> {
    s.trim().parse()
}
10. Pattern Matching

RUST
let x = 5;

// match with literals, ranges, binding
match x {
    1        => println!("one"),
    2 | 3    => println!("two or three"),
    4..=6    => println!("four through six"),
    n        => println!("other: {}", n),
}

// Destructuring a struct
let Point { x, y } = Point::new(1.0, 2.0);

// if let — match one pattern, ignore rest
if let Some(v) = some_number { println!("got {}", v); }

// let else — destructure or return/continue/break
let Some(v) = some_number else { return; };

// Match guard
let num = Some(4);
match num {
    Some(n) if n < 5 => println!("less than five: {}", n),
    Some(n)          => println!("{}", n),
    None             => (),
}
11. Traits

RUST
// Trait definition
trait Summary {
    fn summarize(&self) -> String;
    fn preview(&self) -> String {      // default implementation
        format!("{}...", &self.summarize()[..20])
    }
}

// Implementing a trait
struct Article { title: String, body: String }

impl Summary for Article {
    fn summarize(&self) -> String {
        format!("{}: {}", self.title, self.body)
    }
}

// impl Trait syntax in parameters
fn notify(item: &impl Summary) {
    println!("{}", item.summarize());
}

// Derive macros (auto-implement traits)
#[derive(Debug, Clone, PartialEq)]
struct Config { debug: bool, level: u8 }
12. Generics

RUST
use std::fmt::Display;

// Generic function
fn largest<T: PartialOrd>(list: &[T]) -> &T {
    let mut l = &list[0];
    for item in list { if item > l { l = item; } }
    l
}

// Generic struct
struct Wrapper<T> { value: T }

// where clause for complex bounds
fn print_pair<T, U>(a: T, b: U)
where
    T: Display + Clone,
    U: Display,
{
    println!("{} {}", a, b);
}
13. Error Handling

RUST
use std::fs;
use std::io;

// ? operator — propagates errors automatically
fn read_file(path: &str) -> Result<String, io::Error> {
    let contents = fs::read_to_string(path)?;
    Ok(contents.trim().to_string())
}

// Combinators
let n: i32 = "42".parse().unwrap_or(0);
let n2 = "x".parse::<i32>().unwrap_or_else(|_| -1);
let mapped = "5".parse::<i32>().map(|n| n * 2);   // Ok(10)

// Boxed error (accept any error type)
fn flexible() -> Result<(), Box<dyn std::error::Error>> {
    let _n: i32 = "42".parse()?;
    Ok(())
}

// thiserror — derive Error on custom types (add to Cargo.toml first)
// use thiserror::Error;
// #[derive(Debug, Error)]
// enum AppError {
//     #[error("not found: {0}")]
//     NotFound(String),
//     #[error(transparent)]
//     Io(#[from] io::Error),
// }
14. Iterators

RUST
let v = vec![1, 2, 3, 4, 5, 6];

// Lazy adaptor chain — no work until collect()
let result: Vec<i32> = v.iter()
    .filter(|&&x| x % 2 == 0)
    .map(|&x| x * x)
    .collect();                       // [4, 16, 36]

// Common consuming adaptors
let sum:   i32 = v.iter().sum();      // 21
let prod:  i32 = v.iter().product();  // 720
let count: usize = v.iter().filter(|&&x| x > 3).count(); // 3
let any  = v.iter().any(|&x| x > 5); // true
let all  = v.iter().all(|&x| x > 0); // true
let max  = v.iter().max();            // Some(6)
let fold = v.iter().fold(0, |acc, &x| acc + x); // 21

// zip, enumerate, flat_map, chain, take, skip
let pairs: Vec<_> = v.iter().zip(v.iter().rev()).collect();
15. Smart Pointers

Type

Purpose

Thread-safe?

Box<T>

Heap allocation; own exactly one value

Yes (if T: Send)

Rc<T>

Reference-counted shared ownership

No — single thread only

Arc<T>

Atomic ref-counted shared ownership

Yes

RefCell<T>

Interior mutability (borrow checked at runtime)

No

Mutex<T>

Mutual exclusion; safe shared mutation across threads

Yes

RwLock<T>

Multiple readers or one writer

Yes

RUST
use std::rc::Rc;
use std::sync::{Arc, Mutex};

// Box — heap allocate a value
let b: Box<i32> = Box::new(5);

// Rc — shared ownership, single thread
let a = Rc::new(String::from("shared"));
let b = Rc::clone(&a);
println!("refs: {}", Rc::strong_count(&a)); // 2

// Arc + Mutex — shared mutation across threads
let data = Arc::new(Mutex::new(vec![1, 2, 3]));
let data2 = Arc::clone(&data);
std::thread::spawn(move || {
    data2.lock().unwrap().push(4);
}).join().unwrap();
println!("{:?}", data.lock().unwrap()); // [1, 2, 3, 4]
16. Concurrency

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

// Spawn a thread and join it
let handle = thread::spawn(|| {
    println!("from thread");
});
handle.join().unwrap();

// mpsc channel (multiple producer, single consumer)
let (tx, rx) = mpsc::channel();
let tx2 = tx.clone();
thread::spawn(move || tx.send("hello").unwrap());
thread::spawn(move || tx2.send("world").unwrap());
for msg in rx { println!("{}", msg); }

// Arc<Mutex<T>> shared counter
let counter = Arc::new(Mutex::new(0));
let mut handles = vec![];
for _ in 0..5 {
    let c = Arc::clone(&counter);
    handles.push(thread::spawn(move || { *c.lock().unwrap() += 1; }));
}
for h in handles { h.join().unwrap(); }
println!("counter: {}", *counter.lock().unwrap()); // 5
17. Async / Await

RUST
// Requires tokio in Cargo.toml:
// tokio = { version = "1", features = ["full"] }

use tokio::time::{sleep, Duration};

async fn fetch(id: u32) -> String {
    sleep(Duration::from_millis(10)).await;
    format!("data for {}", id)
}

#[tokio::main]
async fn main() {
    // Sequential await
    let result = fetch(1).await;
    println!("{}", result);

    // Concurrent with tokio::join!
    let (a, b) = tokio::join!(fetch(2), fetch(3));
    println!("{} {}", a, b);

    // Spawn an independent task
    let handle = tokio::spawn(async { fetch(4).await });
    println!("{}", handle.await.unwrap());
}
18. Common Cargo Commands

Bash
cargo new my_project        # create new binary crate
cargo new --lib my_lib      # create new library crate
cargo build                 # compile (debug)
cargo build --release       # compile (optimised)
cargo run                   # build + run
cargo run -- arg1 arg2      # pass arguments
cargo test                  # run all tests
cargo test my_test          # run tests matching name
cargo check                 # fast type-check without linking
cargo clippy                # linter
cargo fmt                   # format code
cargo doc --open            # build + open docs in browser
cargo add serde             # add a dependency
cargo add serde --features derive
cargo update                # update Cargo.lock
cargo tree                  # print dependency tree
cargo publish               # publish crate to crates.io
Success
Bookmark this page and return whenever you need a quick reminder of Rust syntax. Each topic links to a dedicated tutorial page in the sidebar for deeper coverage.