🦀 Complete Rust Reference
Core Language Basics
let x = 5;
let mut y = 5;
const MAX_POINTS: u32 = 100;
static LANGUAGE: &str = "Rust";
let i: i32 = -42;
let u: u32 = 42;
let f: f64 = 4.2;
let b: bool = true;
let c: char = 'c';
let unit: () = ();
let tup: (i32, f64) = (1, 2.0);
let (x, y) = tup;
let arr: [i32; 5] = [1, 2, 3, 4, 5];
let first = arr[0];
let s1: &str = "Hello";
let s2: String = String::from("World");
let s3 = s1.to_string();
let s4 = format!("{} {}", s1, s2);
fn add (x: i32, y: i32) -> i32 {
x + y
}
let add_one = |x: i32| x + 1;
let add_two = |x| {
let y = 2;
x + y
};
Control Flow & Pattern Matching
let number = if condition { 5 } else { 6 };
match number {
0 => println!("zero"),
1..=5 => println!("one through five"),
n if n < 0 => println!("negative"),
_ => println!("something else"),
}
loop {
break 5;
}
while condition {
}
for element in iterator {
}
if let Some(x) = optional {
println!("{}", x);
}
while let Some(x) = stack.pop() {
println!("{}", x);
}
match complex_value {
Person { name: "Steve", age: 20..=30 } => {},
Point { x: 0, y } => {},
Some(Value::Integer(5..=10)) => {},
[first, .., last] => {},
(x, _) if x > 0 => {},
_ => {},
}
Types, Traits & Implementations
struct Point <T> {
x: T,
y: T,
}
impl <T> Point<T> {
fn new (x: T, y: T) -> Self {
Point { x, y }
}
}
enum Option <T> {
Some(T),
None,
}
enum Result <T, E> {
Ok(T),
Err(E),
}
trait Display {
fn fmt (&self, f: &mut Formatter) -> Result;
fn to_string (&self) -> String {
}
}
impl Display for Point<i32> {
fn fmt (&self, f: &mut Formatter) -> Result {
write!(f, "({}, {})", self.x, self.y)
}
}
fn print_type <T: Display + Clone>(t: T) {
println!("{}", t);
}
fn complex_function <T, U>(t: T, u: U) -> i32
where
T: Display + Clone,
U: Clone + Debug,
{
}
trait Container {
type A;
fn get (&self) -> &Self::A;
}
type Result<T> = std::result::Result<T, Error>;
Memory Management & References
let s1 = String::from("hello");
let s2 = s1;
fn calculate_length (s: &String) -> usize {
s.len()
}
fn change (s: &mut String) {
s.push_str(" world");
}
struct Reference <'a, T> {
r: &'a T,
}
impl <'a, T> Reference<'a, T> {
fn get_ref (&self) -> &'a T {
self.r
}
}
fn longest <'a, 'b>(x: &'a str, y: &'b str) -> &'a str {
if x.len() > y.len() { x } else { x }
}
use std::rc::Rc;
use std::cell::RefCell;
let data = Rc::new(5);
let reference = Rc::clone(&data);
let cell = RefCell::new(5);
*cell.borrow_mut() += 1;
Input/Output Operations
use std::io::{self, Write, Read, BufRead};
let mut input = String::new();
io::stdin().read_line(&mut input)?;
println!("Hello, {}!", name);
io::stdout().write_all(b"Hello\n")?;
use std::fs::{self, File};
use std::path::Path;
let contents = fs::read_to_string("file.txt")?;
let file = File::open("file.txt")?;
let reader = io::BufReader::new(file);
for line in reader
for line in reader.lines() {
println!("{}", line?);
}
let mut file = File::create("output.txt")?;
file.write_all(b"Hello, world!")?;
let path = Path::new("directory/file.txt");
fs::create_dir_all(path.parent().unwrap())?;
for entry in fs::read_dir(".")? {
let entry = entry?;
println!("{}", entry.path().display());
}
let file = File::open("file.txt")?;
let mut reader = io::BufReader::new(file);
let mut buffer = Vec::new();
reader.read_to_end(&mut buffer)?;
Error Handling
enum Result <T, E> {
Ok(T),
Err(E),
}
#[derive(Debug)]
enum AppError {
IoError(std::io::Error),
ParseError(std::num::ParseIntError),
Custom(String),
}
impl From<std::io::Error> for AppError {
fn from (err: std::io::Error) -> Self {
AppError::IoError(err)
}
}
fn process_data () -> Result<(), AppError> {
let file = File::open("data.txt")?;
let parsed = "123".parse::<i32>()
.map_err(AppError::ParseError)?;
file.read_to_string(&mut s)
.unwrap();
.expect("Failed to read");
.unwrap_or(default);
.unwrap_or_else(|_| default);
match operation() {
Ok(value) => println!("Success: {}", value),
Err(e) => eprintln!("Error: {}", e),
}
Ok(())
}
Async Programming
async fn fetch_data () -> Result<String, Error> {
let response = client
.get("https://api.example.com")
.send()
.await?;
Ok(response.text().await?)
}
async fn process () {
let data = fetch_data().await?;
let result = process_data(data).await?;
}
use futures::{
future::{self, Future},
stream::{self, Stream},
};
let results = future::join_all(vec![
fetch_data(),
fetch_other_data(),
]).await;
#[tokio::main]
async fn main () {
let handle = tokio::spawn(async {
process_data().await
});
handle.await?;
}
Testing
#[cfg(test)]
mod tests {
use super ::*;
#[test]
fn test_addition () {
assert_eq!(add(2, 2), 4);
assert_ne!(add(2, 2), 5);
assert!(value > 0);
}
#[test]
#[should_panic(expected = "panic message")]
fn test_panic () {
panic!("panic message");
}
#[test]
fn test_result () -> Result<(), String> {
if 2 + 2 == 4 {
Ok(())
} else {
Err(String::from("two plus two does not equal four"))
}
}
}
use my_crate;
#[test]
fn test_external_api () {
my_crate::public_api();
}
#[test]
#[ignore]
#[should_panic]
#[timeout(1000)]
#[bench]
fn bench_addition (b: &mut Bencher) {
b.iter(|| add(2, 2));
}
Standard Library Features
use std::collections::{HashMap, HashSet, VecDeque, BinaryHeap};
let mut map = HashMap::new();
map.insert("key", "value");
let mut set: HashSet<i32> = [1, 2, 3].iter().cloned().collect();
let sum: i32 = (0..5)
.filter(|x| x % 2 == 0)
.map(|x| x * x)
.sum();
use std::sync::{Arc, Mutex};
let shared = Arc::new(Mutex::new(vec![]));
use std::thread;
let handle = thread::spawn(|| {
});
handle.join().unwrap();
use std::sync::mpsc;
let (tx, rx) = mpsc::channel();
tx.send(42).unwrap();
let received = rx.recv().unwrap();
Macros & Meta-programming
macro_rules! vec_of_squares {
($($x:expr),*) => {
vec! [$($x * $x),*]
};
}
#[derive(Debug, Clone)]
#[serde(rename_all = "camelCase")]
struct Point {
x: f64,
y: f64,
}
#[proc_macro_derive(MyTrait)]
pub fn my_trait_derive (input: TokenStream) -> TokenStream {
}
println!("Formatted {}", string);
format!("Format without printing {}", string);
vec![1, 2, 3];
assert!(condition);
assert_eq!(left, right);
include_str!("file.txt");
Common Design Patterns
struct RequestBuilder {
url: String,
method: String,
headers: HashMap<String, String>,
}
impl RequestBuilder {
fn new (url: &str) -> Self {
}
fn method (mut self, method: &str) -> Self {
self.method = method.to_string();
self
}
}
struct Connection <State> {
state: PhantomData<State>,
}
impl <State> Connection<State> {
fn connect (self) -> Connection<Connected> {
}
}
struct ResourceGuard <T> {
resource: T,
}
impl <T> Drop for ResourceGuard<T> {
fn drop (&mut self) {
}
}
Concurrency Patterns
use std::sync::mpsc;
let (tx, rx) = mpsc::channel();
crossbeam::scope(|scope| {
scope.spawn(move |_| {
tx.send(42).unwrap();
});
});
let data = Arc::new(Mutex::new(vec![]));
let data_clone = Arc::clone(&data);
struct Actor {
receiver: mpsc::Receiver<Message>,
state: ActorState,
}
impl Actor {
async fn run (&mut self) {
while let Some(msg) = self.receiver.recv().await {
self.handle_message(msg).await;
}
}
}
FFI & Unsafe Code
#[link(name = "my_c_lib")]
extern "C" {
fn c_function (x: i32) -> i32;
}
unsafe {
let ptr = &num as *const i32;
println!("Location: {:?}", ptr);
}
let mut num = 5;
let r1 = &num as *const i32;
let r2 = &mut num as *mut i32;
unsafe trait Scary { }
unsafe impl Scary for i32 { }
Web & Network Programming
let response = reqwest::Client::new()
.get("https://api.example.com")
.header("Authorization", "Bearer token")
.send()
.await?;
use tokio::net::TcpListener;
#[tokio::main]
async fn main () -> Result<()> {
let listener = TcpListener::bind("127.0.0.1:8080").await?;
while let Ok((socket, _)) = listener.accept().await {
tokio::spawn(async move {
process_socket(socket).await
});
}
}
use tokio_tungstenite;
let (ws_stream, _) = connect_async("ws://localhost:8080")
.await?;
Database Access
let pool = PgPoolOptions::new()
.max_connections(5)
.connect("postgres://user:pass@localhost/db").await?;
let row: (i64,) = sqlx::query_as(
"SELECT $1"
)
.bind(150_i64)
.fetch_one(&pool).await?;
#[derive(Queryable)]
struct Post {
id: i32,
title: String,
body: String,
}
diesel::insert_into(posts::table)
.values(&new_post)
.execute(&mut conn)?;
Tooling & Development
cargo new project_name
cargo build --release
cargo test -- --nocapture
cargo bench
cargo doc --open
cargo clippy
cargo fmt
[workspace]
members = [
"core",
"cli",
"web",
]
[features]
default = ["std"]
std = []
alloc = []
[dev-dependencies]
criterion = "0.3"
mockall = "0.11"
tokio-test = "0.4"
Command Line Applications with Clap
use clap::Parser;
#[derive(Parser)]
#[command(author, version, about)]
struct Cli {
#[arg(short, long, default_value = "default")]
name: String,
#[arg(short, long)]
count: usize,
#[arg(short, long)]
verbose: bool,
#[arg(short, long, num_args = 1..)]
files: Vec<PathBuf>,
#[command(subcommand)]
command: Option<Commands>,
}
#[derive(Subcommand)]
enum Commands {
Add {
name: String,
},
Remove {
#[arg(short, long)]
force: bool,
},
}
fn main () {
let cli = Cli::parse();
match cli.command {
Some(Commands::Add { name }) => {
println!("Adding {}", name);
}
Some(Commands::Remove { force }) => {
println!("Removing with force = {}", force);
}
None => {}
}
}
Serialization with Serde & JSON Processing
use serde::{Serialize, Deserialize};
#[derive(Serialize, Deserialize, Debug)]
#[serde(rename_all = "camelCase")]
struct User {
user_id: u64,
#[serde(rename = "displayName")]
name: String,
#[serde(default)]
active: bool,
#[serde(skip_serializing_if = "Option::is_none")]
email: Option<String>,
#[serde(flatten)]
metadata: HashMap<String, Value>,
}
fn process_json () -> Result<()> {
let json_str = r#"{"userId": 1, "name": "John"}"#;
let user: User = serde_json::from_str(json_str)?;
let value: Value = serde_json::from_str(json_str)?;
println!("Name: {}", value["name"]);
let json = serde_json::to_string_pretty(&user)?;
use serde_json::Deserializer;
let stream = Deserializer::from_str(json_str)
.into_iter::();
#[derive(Serialize)]
struct Custom <T> {
data: T,
#[serde(serialize_with = "serialize_datetime")]
timestamp: DateTime<Utc>,
}
Ok(())
}
Advanced Error Handling Patterns
#[derive(Debug, thiserror::Error)]
enum AppError {
#[error("IO error: {0}")]
Io(#[from] std::io::Error),
#[error("Parse error: {0}")]
Parse(#[from] std::num::ParseIntError),
#[error("Database error: {0}")]
Database(#[from] sqlx::Error),
#[error("Validation error: {msg}")]
Validation { msg: String, code: u32 },
}
use anyhow::{Context, Result};
fn read_config () -> Result<Config> {
std::fs::read_to_string("config.json")
.context("Failed to read config file")?
.parse()
.context("Failed to parse config file")
}
impl From<AppError> for HttpResponse {
fn from (error: AppError) -> Self {
match error {
AppError::Validation { msg, code } =>
HttpResponse::BadRequest()
.json(json!({ "error": msg, "code": code })),
_ => HttpResponse::InternalServerError()
.json(json!({ "error": "Internal server error" }))
}
}
}
fn process_data () -> Result<(), AppError> {
let results: Result, _> = items
.into_iter()
.map(process_item)
.collect();
results?
.into_iter()
.try_for_each(validate_item)?;
Ok(())
}
Advanced Async Patterns
use futures::stream::{self, StreamExt};
async fn process_stream () {
stream::iter(0..100)
.chunks(10)
.for_each_concurrent(4, |chunk| async move {
process_chunk(chunk).await
})
.await;
}
struct Pool <T> {
resources: Arc<Sempahore>,
items: Arc<Mutex<Vec<T>>>,
}
use tokio::time::{timeout, Duration};
async fn with_timeout <F, T>(
duration: Duration,
future: F
) -> Result<T>
where
F: Future<Output = T>,
{
timeout(duration, future).await?
}
async fn with_retry <F, Fut, T>(
f: F,
max_retries: u32,
) -> Result<T>
where
F: Fn() -> Fut,
Fut: Future<Output = Result<T>>,
{
let mut retries = 0;
let mut delay = Duration::from_millis(100);
loop {
match f().await {
Ok(value) => return Ok(value),
Err(e) if retries < max_retries => {
retries += 1;
sleep(delay).await;
delay *= 2;
}
Err(e) => return Err(e),
}
}
}
struct Actor {
receiver: mpsc::Receiver<Message>,
state: ActorState,
}
impl Actor {
async fn run (&mut self) {
while let Some(msg) = self.receiver
.recv()
.await
{
self.handle_message(msg).await;
}
}
}
Advanced Testing Patterns
use proptest::prelude::*;
proptest! {
#[test]
fn test_parse_never_crashes (s: String) {
let _ = parse_input(&s);
}
}
#[rstest]
#[case(2, 2, 4)]
#[case(3, 3, 9)]
#[case(4, 4, 16)]
fn test_multiply (
#[case] a: i32,
#[case] b: i32,
#[case] expected: i32,
) {
assert_eq!(multiply(a, b), expected);
}
#[automock]
trait Database {
async fn get_user (&self, id: u64) -> Result<User>;
}
#[tokio::test]
async fn test_with_mock () {
let mut mock = MockDatabase::new();
mock.expect_get_user()
.returning(|_| Ok(User::default()));
}
#[test]
fn test_snapshot () {
let data = process_complex_data();
insta::assert_yaml_snapshot!(data);
}
#[tokio::test]
async fn test_concurrent () {
let (tx, rx) = mpsc::channel(10);
tokio::spawn(async move {
process_messages(rx).await
});
tx.send(Message::new()).await?;
}
#[tokio::test]
async fn test_with_postgres () {
let container = PostgresContainer::new();
let pool = create_connection_pool(
container.connection_string()
).await?;
}
use criterion::{criterion_group, criterion_main, Criterion};
fn benchmark (c: &mut Criterion) {
c.bench_function("process_data", |b| {
b.iter(|| process_data(black_box(input)))
});
}
Tokio Runtime & Async Primitives
#[tokio::main]
async fn main () {
let runtime = Runtime::new()
.worker_threads(4)
.enable_all()
.build()
.unwrap();
let runtime = Runtime::new()
.basic_scheduler()
.enable_all()
.build()
.unwrap();
}
let handle = tokio::spawn(async {
process_data().await
});
let (result1, result2) = tokio::join!(
async_operation1(),
async_operation2()
);
tokio::select! {
result = async_operation1() => {
println!("Operation 1 completed first");
}
result = async_operation2() => {
println!("Operation 2 completed first");
}
}
use tokio::time::{sleep, timeout, Duration};
sleep(Duration::from_secs(1)).await;
let result = timeout(
Duration::from_secs(5),
async_operation()
).await??;
let mut interval = tokio::time::interval(
Duration::from_secs(1)
);
loop {
interval.tick().await;
perform_periodic_task().await;
}
use tokio::sync::{mpsc, oneshot, broadcast, watch};
let (tx, mut rx) = mpsc::channel(32);
let (tx, mut rx1) = broadcast::channel(16);
let mut rx2 = tx.subscribe();
let (tx, mut rx) = watch::channel("initial value");
let (tx, rx) = oneshot::channel();
use tokio::sync::{Mutex, RwLock, Semaphore};
let mutex = Arc::new(Mutex::new(0));
{
let mut lock = mutex.lock().await;
*lock += 1;
}
let rwlock = Arc::new(RwLock::new(vec![]));
{
let mut write = rwlock.write().await;
write.push(1);
}
let semaphore = Arc::new(Semaphore::new(3));
{
let permit = semaphore.acquire().await?;
perform_limited_task().await;
}
use tokio::io::{AsyncReadExt, AsyncWriteExt};
let mut file = tokio::fs::File::create("file.txt").await?;
file.write_all(b"Hello").await?;
let listener = TcpListener::bind("127.0.0.1:8080").await?;
while let Ok((socket, addr)) = listener.accept().await {
tokio::spawn(async move {
process_socket(socket).await
});
}
Standard Library Collections & Data Structures
let mut vec: Vec<i32> = Vec::new();
vec.push(1);
vec.extend([2, 3, 4]);
vec.insert(1, 5);
vec.remove(0);
vec.drain(1..3);
vec.retain(|&x| x % 2 == 0);
vec.chunks(2)
.filter(|chunk| chunk.len() == 2)
.for_each(|chunk| println!("{:?}", chunk));
vec.windows(2)
.map(|window| window[0] + window[1])
.collect::<Vec<_>>();
let mut deque = VecDeque::new();
deque.push_front(1);
deque.push_back(2);
deque.pop_front();
deque.pop_back();
let mut list = LinkedList::new();
list.push_back(1);
list.push_front(0);
list.append(&mut other_list);
list.splice(1..3, some_iter);
let mut map = HashMap::new();
map.insert("key", "value");
map.entry("key")
.or_insert("default");
map.entry("key")
.and_modify(|v| *v = "new value")
.or_insert("default");
map.retain(|&k, &mut v| k.len() > 3);
map.get_key_value("key");
map.remove_entry("key");
let mut set = HashSet::new();
set.insert(1);
set.remove(&1);
set.contains(&1);
let union: HashSet<_> = set1.union(&set2).collect();
let intersection = set1.intersection(&set2);
let difference = set1.difference(&set2);
let symmetric_difference = set1.symmetric_difference(&set2);
let mut btree = BTreeMap::new();
btree.insert(1, "one");
btree.range(1..3);
btree.first_key_value();
btree.last_key_value();
let mut heap = BinaryHeap::new();
heap.push(1);
heap.pop();
heap.peek();
heap.into_sorted_vec();
let mut string = String::from("hello");
string.push_str(" world");
string.replace("hello", "hi");
string.split_whitespace()
.map(str::to_uppercase)
.collect::<Vec<_>>();
string.chars().rev().collect::<String>();
string.lines()
.filter(|line| !line.is_empty())
.collect::<Vec<_>>();
use std::collections::{BTreeSet, HashMap};
let mut btree_set = BTreeSet::new();
btree_set.insert(1);
btree_set.range(1..3);
use smallvec::{SmallVec, smallvec};
let mut small_vec: SmallVec<[u8; 4]> = smallvec![1, 2, 3];
Common Programming Tasks
use std::fs;
use std::io::{self, Read, Write, BufRead, BufReader};
fn read_file (path: &str) -> io::Result<String> {
fs::read_to_string(path)
}
fn process_lines (path: &str) -> io::Result<()> {
let file = File::open(path)?;
let reader = BufReader::new(file);
for line in reader.lines() {
let line = line?;
}
Ok(())
}
fn save_data (path: &str, data: &str) -> io::Result<()> {
fs::write(path, data)
}
fn append_to_file (path: &str, data: &str) -> io::Result<()> {
let mut file = OpenOptions::new()
.append(true)
.create(true)
.open(path)?;
writeln!(file, "{}", data)
}
fn file_operations () -> io::Result<()> {
if Path::new("file.txt").exists() {
fs::copy("file.txt", "backup.txt")?;
fs::rename("file.txt", "new_name.txt")?;
fs::remove_file("old_file.txt")?;
}
fs::create_dir_all("nested/dirs")?;
for entry in fs::read_dir(".")? {
let entry = entry?;
println!("{}", entry.path().display());
}
Ok(())
}
use clap::Parser;
#[derive(Parser)]
#[command(name = "myapp")]
#[command(about = "A simple utility program")]
struct Args {
#[arg(short, long)]
input: PathBuf,
#[arg(short, long)]
output: Option<PathBuf>,
#[arg(short, long)]
verbose: bool,
}
fn main () -> Result<(), Box<dyn Error>> {
let args = Args::parse();
let content = fs::read_to_string(&args.input)
.with_context(|| format!("Failed to read {}", args.input.display()))?;
let processed = process_content(&content)?;
match args.output {
Some(path) => fs::write(path, processed)?,
None => println!("{}", processed),
}
Ok(())
}
use std::env;
fn env_operations () {
let key = env::var("HOME").unwrap_or_default();
env::set_var("MY_VAR", "value");
for (key, value) in env::vars() {
println!("{}: {}", key, value);
}
}
fn text_processing (text: &str) -> String {
text.lines()
.filter(|line| !line.trim().is_empty())
.map(|line| line.trim().to_uppercase())
.collect::<Vec<_>>()
.join("\n")
}
fn setup_logging () -> Result<(), fern::InitError> {
fern::Dispatch::new()
.format(|out, message, record| {
out.finish(format_args!(
"[{}][{}] {}",
record.level(),
record.target(),
message
))
})
.level(log::LevelFilter::Info)
.chain(std::io::stdout())
.chain(fern::log_file("program.log")?)
.apply()?;
Ok(())
}
use serde::{Serialize, Deserialize};
#[derive(Serialize, Deserialize)]
struct Config {
api_key: String,
max_retries: u32,
timeout: u64,
}
fn load_config () -> Result<Config, Box<dyn Error>> {
let config_path = get_config_path()?;
let contents = fs::read_to_string(config_path)?;
Ok(toml::from_str(&contents)?)
}
use indicatif::{ProgressBar, ProgressStyle};
fn process_with_progress <T>(items: Vec<T>) {
let pb = ProgressBar::new(items.len() as u64);
pb.set_style(ProgressStyle::default_bar()
.template("[{elapsed_precise}] {bar:40.cyan/blue} {pos}/{len}")
.unwrap());
for item in items {
pb.inc(1);
}
pb.finish_with_message("done");
}
fn string_operations (text: &str) -> String {
let trimmed = text.trim();
let parts: Vec<&str> = text.split(',').collect();
let replaced = text.replace("old", "new");
let upper = text.to_uppercase();
let lower = text.to_lowercase();
if let Some(start) = text.find("start") {
if let Some(end) = text.find("end") {
return text[start..end].to_string();
}
}
String::new()
}