Quick reference cards for common Rust patterns and syntax. Bookmark this page for instant access while coding.
Ownership ve Borrowing
let s1 = String::from("hello");
let s2 = s1; // s1 is moved, no longer valid
// println!("{}", s1); // Error!let s1 = String::from("hello");
let s2 = s1.clone(); // Deep copy
println!("{} {}", s1, s2); // Both validlet s = String::from("hello");
let r1 = &s; // Immutable borrow
let r2 = &s; // Multiple immutable OK
println!("{} {}", r1, r2);let mut s = String::from("hello");
let r = &mut s; // Mutable borrow
r.push_str(" world");
// Only one mutable borrow at a timefn longest<'a>(x: &'a str, y: &'a str) -> &'a str {
if x.len() > y.len() { x } else { y }
}Yaygın Tipler
let some_value: Option<i32> = Some(5);
let no_value: Option<i32> = None;
// Pattern matching
match some_value {
Some(v) => println!("Got: {}", v),
None => println!("Nothing"),
}
// Or use if let
if let Some(v) = some_value {
println!("Got: {}", v);
}fn divide(a: i32, b: i32) -> Result<i32, String> {
if b == 0 {
Err("Division by zero".to_string())
} else {
Ok(a / b)
}
}
// Use ? operator
fn calc() -> Result<i32, String> {
let result = divide(10, 2)?;
Ok(result * 2)
}let mut v: Vec<i32> = Vec::new();
let v2 = vec![1, 2, 3]; // Macro
v.push(1);
v.push(2);
let first = &v[0]; // May panic
let safe = v.get(0); // Returns Optionuse std::collections::HashMap;
let mut map = HashMap::new();
map.insert("key", "value");
// Entry API
map.entry("key2").or_insert("default");
// Get value
if let Some(v) = map.get("key") {
println!("{}", v);
}Trait ve Generic'ler
trait Summary {
fn summarize(&self) -> String;
// Default implementation
fn default_summary(&self) -> String {
String::from("Read more...")
}
}struct Article { title: String, content: String }
impl Summary for Article {
fn summarize(&self) -> String {
format!("{}: {}", self.title, &self.content[..50])
}
}// Generic function with trait bound
fn print_summary<T: Summary>(item: &T) {
println!("{}", item.summarize());
}
// Multiple bounds
fn complex<T: Clone + Debug>(item: T) { }
// Where clause
fn verbose<T, U>(t: T, u: U) -> i32
where
T: Display + Clone,
U: Clone + Debug,
{ 42 }// Return type
fn make_iter() -> impl Iterator<Item = i32> {
(0..10).filter(|x| x % 2 == 0)
}
// Parameter type (same as generic)
fn process(item: impl Summary) {
println!("{}", item.summarize());
}Akıllı İşaretçiler
// Heap allocation
let b = Box::new(5);
println!("{}", b);
// Recursive types
enum List {
Cons(i32, Box<List>),
Nil,
}use std::rc::Rc;
let a = Rc::new(5);
let b = Rc::clone(&a); // Increment ref count
let c = Rc::clone(&a);
println!("Count: {}", Rc::strong_count(&a)); // 3use std::sync::Arc;
use std::thread;
let data = Arc::new(vec![1, 2, 3]);
let handles: Vec<_> = (0..3).map(|_| {
let data = Arc::clone(&data);
thread::spawn(move || {
println!("{:?}", data);
})
}).collect();use std::cell::RefCell;
let data = RefCell::new(5);
// Borrow at runtime
*data.borrow_mut() += 1;
println!("{}", data.borrow()); // 6
// Interior mutability pattern
let shared = Rc::new(RefCell::new(vec![]));Async/Await
async fn fetch_data() -> Result<String, Error> {
let response = reqwest::get("https://api.example.com")
.await?;
response.text().await
}use tokio;
#[tokio::main]
async fn main() {
let handle = tokio::spawn(async {
// Async work
42
});
let result = handle.await.unwrap();
}use tokio::select;
async fn race() {
select! {
result = async_op1() => {
println!("Op1: {:?}", result);
}
result = async_op2() => {
println!("Op2: {:?}", result);
}
}
}use tokio::join;
async fn parallel() {
let (r1, r2, r3) = join!(
fetch_user(1),
fetch_user(2),
fetch_user(3),
);
// All complete concurrently
}Hata Yönetimi
use thiserror::Error;
#[derive(Error, Debug)]
enum MyError {
#[error("IO error: {0}")]
Io(#[from] std::io::Error),
#[error("Parse error: {msg}")]
Parse { msg: String },
#[error("Not found")]
NotFound,
}fn read_file() -> Result<String, MyError> {
let content = std::fs::read_to_string("file.txt")?;
let parsed = content.parse::<i32>()
.map_err(|e| MyError::Parse {
msg: e.to_string()
})?;
Ok(parsed.to_string())
}let result: Result<i32, &str> = Ok(5);
// Transform Ok value
let doubled = result.map(|x| x * 2);
// Transform Err value
let mapped_err = result.map_err(|e| format!("Error: {}", e));
// Chain operations
let chained = result
.and_then(|x| if x > 0 { Ok(x) } else { Err("negative") });use anyhow::{Context, Result, bail};
fn process() -> Result<()> {
let file = std::fs::read_to_string("config.toml")
.context("Failed to read config")?;
if file.is_empty() {
bail!("Config file is empty");
}
Ok(())
}Iterator'lar
let v = vec![1, 2, 3, 4, 5];
// Transform
let doubled: Vec<_> = v.iter().map(|x| x * 2).collect();
// Filter
let evens: Vec<_> = v.iter().filter(|x| *x % 2 == 0).collect();
// Find
let first_even = v.iter().find(|x| *x % 2 == 0);
// Fold/Reduce
let sum: i32 = v.iter().sum();
let product: i32 = v.iter().product();let result: Vec<i32> = (0..100)
.filter(|x| x % 3 == 0)
.map(|x| x * x)
.take(5)
.collect();
// [0, 9, 36, 81, 144]struct Counter { count: u32 }
impl Iterator for Counter {
type Item = u32;
fn next(&mut self) -> Option<Self::Item> {
self.count += 1;
if self.count < 6 {
Some(self.count)
} else {
None
}
}
}Makrolar
macro_rules! say_hello {
() => {
println!("Hello!");
};
($name:expr) => {
println!("Hello, {}!", $name);
};
}
say_hello!(); // Hello!
say_hello!("World"); // Hello, World!macro_rules! vec_of_strings {
($($x:expr),* $(,)?) => {
vec![$($x.to_string()),*]
};
}
let v = vec_of_strings!["a", "b", "c"];
// vec!["a".to_string(), "b".to_string(), "c".to_string()]use serde::{Serialize, Deserialize};
#[derive(Debug, Clone, Serialize, Deserialize)]
struct User {
name: String,
email: String,
}
// Generates impl blocks automaticallyEşzamanlılık
use std::thread;
let handle = thread::spawn(|| {
println!("Hello from thread!");
42
});
let result = handle.join().unwrap(); // 42use std::sync::mpsc;
let (tx, rx) = mpsc::channel();
thread::spawn(move || {
tx.send("Hello").unwrap();
});
let msg = rx.recv().unwrap(); // "Hello"use std::sync::{Arc, Mutex};
let counter = Arc::new(Mutex::new(0));
let handles: Vec<_> = (0..10).map(|_| {
let counter = Arc::clone(&counter);
thread::spawn(move || {
let mut num = counter.lock().unwrap();
*num += 1;
})
}).collect();
for handle in handles {
handle.join().unwrap();
}use std::sync::RwLock;
let lock = RwLock::new(5);
// Multiple readers
{
let r1 = lock.read().unwrap();
let r2 = lock.read().unwrap();
}
// One writer
{
let mut w = lock.write().unwrap();
*w += 1;
}Test
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_add() {
assert_eq!(add(2, 2), 4);
}
#[test]
#[should_panic(expected = "overflow")]
fn test_panic() {
panic!("overflow");
}
}#[test]
fn test_with_result() -> Result<(), String> {
let value = some_fallible_op()?;
assert_eq!(value, 42);
Ok(())
}assert!(condition);
assert_eq!(left, right);
assert_ne!(left, right);
// With message
assert!(x > 0, "x must be positive, got {}", x);
// Debug assertions (only in debug builds)
debug_assert!(expensive_check());Tasarım Kalıpları
struct ServerBuilder {
host: String,
port: u16,
}
impl ServerBuilder {
fn new() -> Self {
Self { host: "localhost".into(), port: 8080 }
}
fn host(mut self, host: &str) -> Self {
self.host = host.into();
self
}
fn port(mut self, port: u16) -> Self {
self.port = port;
self
}
fn build(self) -> Server {
Server { host: self.host, port: self.port }
}
}
// Usage: ServerBuilder::new().host("0.0.0.0").port(3000).build()trait Shape { fn area(&self) -> f64; }
struct Circle { radius: f64 }
struct Rectangle { width: f64, height: f64 }
impl Shape for Circle {
fn area(&self) -> f64 { 3.14159 * self.radius * self.radius }
}
impl Shape for Rectangle {
fn area(&self) -> f64 { self.width * self.height }
}
fn create_shape(kind: &str) -> Box<dyn Shape> {
match kind {
"circle" => Box::new(Circle { radius: 1.0 }),
"rectangle" => Box::new(Rectangle { width: 2.0, height: 3.0 }),
_ => panic!("Unknown shape"),
}
}trait CompressionStrategy {
fn compress(&self, data: &[u8]) -> Vec<u8>;
}
struct GzipCompression;
struct LzmaCompression;
impl CompressionStrategy for GzipCompression {
fn compress(&self, data: &[u8]) -> Vec<u8> {
// gzip logic
data.to_vec()
}
}
struct Compressor<S: CompressionStrategy> {
strategy: S,
}
impl<S: CompressionStrategy> Compressor<S> {
fn compress(&self, data: &[u8]) -> Vec<u8> {
self.strategy.compress(data)
}
}use std::sync::mpsc::{channel, Sender, Receiver};
struct EventBus<T> {
senders: Vec<Sender<T>>,
}
impl<T: Clone> EventBus<T> {
fn new() -> Self {
Self { senders: vec![] }
}
fn subscribe(&mut self) -> Receiver<T> {
let (tx, rx) = channel();
self.senders.push(tx);
rx
}
fn publish(&self, event: T) {
for sender in &self.senders {
let _ = sender.send(event.clone());
}
}
}Veri Yapıları
struct Node<T> {
value: T,
left: Option<Box<Node<T>>>,
right: Option<Box<Node<T>>>,
}
impl<T: Ord> Node<T> {
fn insert(&mut self, value: T) {
if value < self.value {
match &mut self.left {
Some(left) => left.insert(value),
None => self.left = Some(Box::new(Node {
value, left: None, right: None
})),
}
} else {
match &mut self.right {
Some(right) => right.insert(value),
None => self.right = Some(Box::new(Node {
value, left: None, right: None
})),
}
}
}
}struct Graph {
edges: Vec<Vec<usize>>,
}
impl Graph {
fn new(n: usize) -> Self {
Self { edges: vec![vec![]; n] }
}
fn add_edge(&mut self, from: usize, to: usize) {
self.edges[from].push(to);
}
fn bfs(&self, start: usize) -> Vec<usize> {
use std::collections::VecDeque;
let mut visited = vec![false; self.edges.len()];
let mut queue = VecDeque::from([start]);
let mut order = vec![];
while let Some(node) = queue.pop_front() {
if visited[node] { continue; }
visited[node] = true;
order.push(node);
for &neighbor in &self.edges[node] {
queue.push_back(neighbor);
}
}
order
}
}use std::collections::HashMap;
// Fibonacci with memoization
fn fib(n: u64, cache: &mut HashMap<u64, u64>) -> u64 {
if n <= 1 { return n; }
if let Some(&result) = cache.get(&n) {
return result;
}
let result = fib(n - 1, cache) + fib(n - 2, cache);
cache.insert(n, result);
result
}
// Tabulation (bottom-up)
fn fib_tab(n: usize) -> u64 {
if n <= 1 { return n as u64; }
let mut dp = vec![0u64; n + 1];
dp[1] = 1;
for i in 2..=n {
dp[i] = dp[i-1] + dp[i-2];
}
dp[n]
}use std::collections::HashMap;
struct LRUCache<K, V> {
capacity: usize,
map: HashMap<K, V>,
order: Vec<K>,
}
impl<K: Eq + std::hash::Hash + Clone, V> LRUCache<K, V> {
fn new(capacity: usize) -> Self {
Self { capacity, map: HashMap::new(), order: vec![] }
}
fn get(&mut self, key: &K) -> Option<&V> {
if self.map.contains_key(key) {
self.order.retain(|k| k != key);
self.order.push(key.clone());
}
self.map.get(key)
}
fn put(&mut self, key: K, value: V) {
if self.map.len() >= self.capacity && !self.map.contains_key(&key) {
if let Some(oldest) = self.order.first().cloned() {
self.map.remove(&oldest);
self.order.remove(0);
}
}
self.order.retain(|k| k != &key);
self.order.push(key.clone());
self.map.insert(key, value);
}
}Explore comprehensive tutorials with full working examples in the Software Engineering section.