# Rust Quickstart Reference - Quick Reference - Launch Pad

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

# 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.