__ _______________________ _________._________________________ \_ _____/ \______ \ / _ \ / _____/ / _____/ | | \_ _____/ | __) | _/ / /_\ \ / \ ___ / \ ___ | | | __)_ | \ | | \ / | \ \ \_\ \ \ \_\ \ | |___ | \ \___ / |____|_ / \____|__ / \______ / \______ / |_______ \ /_______ / \/ \/ \/ \/ \/ \/ \/

Rust Quickstart Reference

← Back to quick reference

← Home


Quick reference guide for Rust. Essential syntax, ownership, borrowing, and common patterns.


Hello World

fn main() {
    println!("Hello, World!");  // Semicolons required; braces define scope
}

Variables

let x: i32 = 42;       // Immutable by default
let mut y: i32 = 10;   // Mutable
let name: &str = "Alice";
let flag: bool = true;
let pi: f64 = 3.14;    // Floating point

// Type inference
let z = 100;            // Compiler infers i32
let text = "Hello";     // &str

Control Flow

If/Else

if x > 10 {
    println!("x is big");
} else {
    println!("x is small");
}

if x > 10 {
    println!("big");
} else if x > 5 {
    println!("medium");
} else {
    println!("small");
}

// If as expression
let result = if x > 10 { "big" } else { "small" };

For Loops

for i in 0..5 {         // 0 to 4 (exclusive)
    println!("{}", i);
}

for i in 0..=5 {        // 0 to 5 (inclusive)
    println!("{}", i);
}

let nums = vec![1, 2, 3];
for n in &nums {        // Borrow reference
    println!("{}", n);
}

for (i, n) in nums.iter().enumerate() {
    println!("{}: {}", i, n);
}

While Loops

while y > 0 {
    y -= 1;
    println!("{}", y);
}

// Loop with break
loop {
    if y <= 0 {
        break;
    }
    y -= 1;
}

Functions

fn add(a: i32, b: i32) -> i32 {
    a + b                  // Expression returns value (no semicolon)
}

println!("{}", add(2, 3));

// Explicit return
fn subtract(a: i32, b: i32) -> i32 {
    return a - b;           // Semicolon required with return
}

// Unit type (no return value)
fn greet() {
    println!("Hello!");
}

Vectors / HashMaps

Vectors

let nums = vec![1, 2, 3];   // Dynamic array
for n in &nums {
    println!("{}", n);
}

let mut vec = Vec::new();
vec.push(1);
vec.push(2);
vec.pop();                  // Remove and return last item
vec[0]                      // Access by index
vec.len()                   // Length

HashMaps

use std::collections::HashMap;

let mut person = HashMap::new();
person.insert("name", "Alice");
person.insert("age", "30");
println!("{}", person["name"]);

// Safe access
match person.get("name") {
    Some(value) => println!("{}", value),
    None => println!("Not found"),
}

// Or use unwrap_or
let name = person.get("name").unwrap_or(&"Unknown");

Arrays

let arr = [1, 2, 3];        // Fixed-size array
let arr: [i32; 3] = [1, 2, 3];  // Explicit type and size

Tuples

let point = (3, 4);
let (x, y) = point;         // Destructuring
let x = point.0;            // Access by index

Strings

let s1 = "Hello";           // &str (string slice)
let s2 = String::from("Hello");  // String (owned)
let s3 = s2.clone();        // Clone owned string

// String operations
let mut s = String::from("Hello");
s.push_str(" World");
s.push('!');
let len = s.len();
let slice = &s[0..5];       // String slice

// Formatting
let name = "Alice";
let greeting = format!("Hello, {}!", name);

Ownership & Borrowing

// Ownership
let s1 = String::from("hello");
let s2 = s1;                // s1 moved to s2, s1 no longer valid
// println!("{}", s1);      // Error! s1 no longer owns the value

// Borrowing (references)
let s1 = String::from("hello");
let len = calculate_length(&s1);  // Borrow, don't move
println!("{}", s1);        // Still valid

fn calculate_length(s: &String) -> usize {
    s.len()
}

// Mutable references
let mut s = String::from("hello");
change(&mut s);

fn change(some_string: &mut String) {
    some_string.push_str(", world");
}

Structs

struct Person {
    name: String,
    age: u32,
}

let person = Person {
    name: String::from("Alice"),
    age: 30,
};

println!("{} is {}", person.name, person.age);

// Methods
impl Person {
    fn new(name: String, age: u32) -> Person {
        Person { name, age }
    }
    
    fn greet(&self) {
        println!("Hello, I'm {}", self.name);
    }
}

let person = Person::new(String::from("Alice"), 30);
person.greet();

Enums

enum Direction {
    Up,
    Down,
    Left,
    Right,
}

let dir = Direction::Up;

match dir {
    Direction::Up => println!("Going up"),
    Direction::Down => println!("Going down"),
    Direction::Left => println!("Going left"),
    Direction::Right => println!("Going right"),
}

// Enums with data
enum Option<T> {
    Some(T),
    None,
}

let some_number = Some(5);
let no_number: Option<i32> = None;

Error Handling

// Result type
fn divide(a: f64, b: f64) -> Result<f64, String> {
    if b == 0.0 {
        Err(String::from("Division by zero"))
    } else {
        Ok(a / b)
    }
}

match divide(10.0, 2.0) {
    Ok(result) => println!("Result: {}", result),
    Err(e) => println!("Error: {}", e),
}

// Using unwrap (panics on error)
let result = divide(10.0, 2.0).unwrap();

// Using expect (custom panic message)
let result = divide(10.0, 2.0).expect("Division failed");

// Using ? operator (propagates error)
fn calculate() -> Result<f64, String> {
    let x = divide(10.0, 2.0)?;
    Ok(x * 2.0)
}

File Operations

use std::fs;
use std::io::{self, Write};

// Reading
let content = fs::read_to_string("file.txt")
    .expect("Failed to read file");

// Writing
fs::write("file.txt", "Hello, World!")
    .expect("Failed to write file");

// With error handling
match fs::read_to_string("file.txt") {
    Ok(content) => println!("{}", content),
    Err(e) => println!("Error: {}", e),
}

Tips

  • Rust variables are immutable by default; use mut to allow changes.
  • read_line handles user input; parsing is required for numbers:
    use std::io;
    let mut input = String::new();
    io::stdin().read_line(&mut input).expect("Failed to read");
    let number: i32 = input.trim().parse().expect("Not a number");
  • Ownership and borrowing rules prevent data races — Rust's core safety guarantee.
  • 0..5 ranges are exclusive of the end value; use 0..=5 for inclusive.
  • Everything has a type; Rust's compiler is strict but helpful with error messages.
  • Use & for borrowing (references) and &mut for mutable borrowing.
  • Expressions (no semicolon) return values; statements (with semicolon) return unit ().
  • Use match for pattern matching — exhaustive and powerful.
  • Use Option<T> for values that might not exist, Result<T, E> for operations that might fail.
  • The ? operator is syntactic sugar for propagating errors in functions that return Result.
  • Use unwrap() sparingly — prefer proper error handling with match or ?.
  • Structs define data; impl blocks define methods and associated functions.