Rust Cheatsheet

1. Variables and Data Types

let age: u32 = 30;
let name = "John";  // Type inferred
let pi: f64 = 3.14159;

// Immutable by default
let x = 5;
// Mutable variable
let mut y = 10;
y = 20;

// Constants
const MAX_POINTS: u32 = 100_000;

// Tuples
let person: (&str, u32) = ("John", 30);
println!("Name: {}, Age: {}", person.0, person.1);

// Arrays
let numbers: [i32; 3] = [1, 2, 3];

2. Control Flow (Conditionals and Loops)

// If-else statement
if age > 18 {
  println!("Adult");
} else {
  println!("Minor");
}

// Match expression (like switch)
let day = 2;
match day {
  1 => println!("Monday"),
  2 => println!("Tuesday"),
  _ => println!("Other day"),
}

// Loops
for i in 1..=5 {
  println!("{}", i);
}

// While loop
let mut age = 25;
while age < 30 {
  println!("Age: {}", age);
  age += 1;
}

// Infinite loop
loop {
  println!("Looping forever");
  break;  // Break out of the loop
}

3. Functions and Closures

fn greet(name: &str) -> String {
  format!("Hello, {}!", name)
}

fn add(a: i32, b: i32) -> i32 {
  a + b
}

println!("{}", greet("John"));
println!("{}", add(5, 10));

// Closures
let add_closure = |x: i32, y: i32| -> i32 { x + y };
println!("Sum: {}", add_closure(2, 3));

4. Ownership, Borrowing, and Lifetimes

// Ownership
let s = String::from("Hello");  // Ownership of the string
let s2 = s;  // Ownership moved to s2
// println!("{}", s);  // Error: s no longer valid

// Borrowing (References)
let name = String::from("John");
print_name(&name);  // Borrowing
println!("Name: {}", name);  // Still valid after borrowing

fn print_name(name: &String) {
  println!("Name: {}", name);
}

// Mutable references
let mut age = 25;
add_year(&mut age);
println!("Age: {}", age);

fn add_year(age: &mut u32) {
  *age += 1;
}

// Lifetimes
fn longest<'a>(s1: &'a str, s2: &'a str) -> &'a str {
  if s1.len() > s2.len() {
    s1
  } else {
    s2
  }
}
let result = longest("Hello", "World");

5. Structs and Enums

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

let person = Person {
  name: String::from("John"),
  age: 30,
};
println!("Name: {}, Age: {}", person.name, person.age);

// Tuple Structs
struct Color(i32, i32, i32);
let red = Color(255, 0, 0);

// Enums
enum Direction {
  North,
  South,
  East,
  West,
}

let dir = Direction::North;
match dir {
  Direction::North => println!("Heading North"),
  Direction::South => println!("Heading South"),
  _ => println!("Other direction"),
}

6. Pattern Matching and Option

// Pattern matching with Option
enum Option<T> {
  Some(T),
  None,
}

let maybe_number: Option<i32> = Some(5);
match maybe_number {
  Some(n) => println!("Number: {}", n),
  None => println!("No number"),
}

// If let
if let Some(n) = maybe_number {
  println!("Number: {}", n);
}

7. Error Handling with Result

// Result Type
fn divide(a: i32, b: i32) -> Result<i32, String> {
  if b == 0 {
    Err(String::from("Cannot divide by zero"))
  } else {
    Ok(a / b)
  }
}

let result = divide(10, 0);
match result {
  Ok(val) => println!("Result: {}", val),
  Err(e) => println!("Error: {}", e),
}

// Unwrap
let res = divide(10, 2).unwrap();  // Panics if error
println!("Unwrapped result: {}", res);

8. Traits and Generics

// Trait (similar to interface)
trait Describable {
  fn describe(&self) -> String;
}

struct Dog;
impl Describable for Dog {
  fn describe(&self) -> String {
    String::from("I am a dog")
  }
}

let dog = Dog;
println!("{}", dog.describe());

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

let numbers = vec![1, 2, 3, 4, 5];
println!("Largest: {}", largest(&numbers));

9. Concurrency with Threads

use std::thread;

let handle = thread::spawn(|| {
  for i in 1..5 {
    println!("Thread: {}", i);
    thread::sleep(std::time::Duration::from_millis(500));
  }
});

handle.join().unwrap();
println!("Main thread finished");

10. Async/Await

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

#[tokio::main]
async fn main() {
  let result = do_work().await;
  println!("Result: {}", result);
}

async fn do_work() -> u32 {
  sleep(Duration::from_secs(1)).await;
  42
}

main();

11. Memory Management and Smart Pointers

// Box<T> for heap allocation
let b = Box::new(5);
println!("b = {}", b);

// Rc<T> for reference counting
use std::rc::Rc;
let a = Rc::new(5);
let b = Rc::clone(&a);
println!("a = {}, b = {}", a, b);

// RefCell<T> for mutable borrowing at runtime
use std::cell::RefCell;
let data = RefCell::new(5);
*data.borrow_mut() = 10;
println!("data = {}", data.borrow());

12. File I/O

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

// Writing to a file
let mut file = File::create("output.txt").expect("Unable to create file");
file.write_all(b"Hello, Rust!").expect("Unable to write");

// Reading from a file
let mut file = File::open("output.txt").expect("Unable to open file");
let mut content = String::new();
file.read_to_string(&mut content).expect("Unable to read file");
println!("File content: {}", content);

13. Iterators and Closures

// Creating an iterator
let numbers = vec![1, 2, 3];
let iter = numbers.iter();
for num in iter {
  println!("{}", num);
}

// Using map and collect
let doubled: Vec<i32> = numbers.iter().map(|x| x * 2).collect();
println!("Doubled: {:?}", doubled);

// Filtering
let filtered: Vec<i32> = numbers.iter().filter(|&&x| x > 1).copied().collect();
println!("Filtered: {:?}", filtered);

14. Macros

// Declarative macros
macro_rules! say_hello {
  () => {
    println!("Hello from macro!");
  };
}

say_hello!();

// Procedural macros
use proc_macro;
#[proc_macro]
fn my_macro(input: TokenStream) -> TokenStream {
  // Process macro input here
  input
}