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
}