Rust Cheatsheet
Modules
Use this Rust reference while you build software engineering projects, review code for technical interview prep, or polish examples for a software engineer resume.
Module Basics
Modules organize code into namespaces. Use mod to define a module.
// Inline module mod math { pub fn add(a: i32, b: i32) -> i32 { a + b } pub fn subtract(a: i32, b: i32) -> i32 { a - b } // Nested module pub mod advanced { pub fn square(x: i32) -> i32 { x * x } } } fn main() { let sum = math::add(3, 4); let sq = math::advanced::square(5); }
Visibility (pub)
By default everything is private — only accessible within the same module and its children.
mod outer { pub struct Public; struct Private; // only accessible in `outer` pub mod inner { pub fn visible() {} fn hidden() {} // pub(super) — accessible to parent module only pub(super) fn to_parent() {} // pub(crate) — accessible anywhere in the crate pub(crate) fn crate_wide() {} } } // Visibility levels: // private (default) — current module and its descendants // pub(self) — same as private // pub(super) — parent module // pub(crate) — anywhere in the crate // pub(in path) — specific ancestor module // pub — anywhere (public API)
Struct field visibility:
pub struct Config { pub host: String, // public field port: u16, // private — external code can't access directly pub(crate) timeout: u64, // crate-visible } impl Config { pub fn new(host: String, port: u16) -> Self { Config { host, port, timeout: 30 } } pub fn port(&self) -> u16 { self.port } // getter for private field }
File-Based Modules
The compiler looks for module code in files automatically:
src/ ├── main.rs (or lib.rs for a library) ├── math.rs — defines `mod math` content ├── math/ │ └── mod.rs — alternative: defines `mod math` content ├── utils.rs └── utils/ ├── mod.rs ├── string.rs — `mod string` inside utils/mod.rs └── number.rs
In main.rs:
mod math; // compiler finds src/math.rs or src/math/mod.rs mod utils; fn main() { let result = math::add(1, 2); }
src/math.rs:
pub fn add(a: i32, b: i32) -> i32 { a + b } pub mod trig; // compiler finds src/math/trig.rs
Inline declaration in a non-root file (Rust 2018+):
// src/utils/mod.rs or src/utils.rs pub mod string; // finds src/utils/string.rs pub mod number; // finds src/utils/number.rs
use — Bringing Paths into Scope
use std::collections::HashMap; use std::io::{self, Read, Write}; // import multiple from same path // Rename with `as` use std::fmt::Result as FmtResult; use std::io::Result as IoResult; // Glob import (use sparingly) use std::collections::*; // Re-export (make visible to users of this module) pub use crate::math::add; pub use std::collections::HashMap; // re-export a dependency fn main() { let mut m = HashMap::new(); m.insert("key", 1); }
Nested path syntax:
use std::{ cmp::Ordering, collections::{HashMap, HashSet}, fmt::{self, Display, Debug}, io::{self, Read, Write, BufReader}, };
Absolute vs Relative Paths
// Absolute paths start with crate name or `crate` crate::utils::format_name("alice"); std::collections::HashMap::new(); // Relative paths start from the current module utils::format_name("alice"); // if utils is a sibling module // super — parent module mod child { use super::parent_fn; // function in parent module pub fn call() { super::parent_fn(); } } // self — current module (sometimes needed in use statements) use self::sibling_module::something;
Crates
A crate is the root compilation unit. Two types:
- Binary crate: has a main() function, produces an executable.
- Library crate: lib.rs as root, produces a library for other crates.
# Cargo.toml [package] name = "my_crate" version = "0.1.0" [lib] name = "my_crate" # name of the library crate (default: package name) path = "src/lib.rs" # default [[bin]] name = "my_tool" # binary name path = "src/main.rs" # default [[bin]] name = "other_tool" path = "src/bin/other.rs"
Accessing your library from binaries in the same package:
// src/main.rs use my_crate::some_public_fn;
Workspaces
A workspace contains multiple packages sharing Cargo.lock and output dir.
# workspace root Cargo.toml
[workspace]
members = [
"core",
"cli",
"api",
]
resolver = "2" # use v2 feature resolver (recommended)my_workspace/ ├── Cargo.toml (workspace manifest) ├── Cargo.lock (shared) ├── core/ │ ├── Cargo.toml │ └── src/lib.rs ├── cli/ │ ├── Cargo.toml │ └── src/main.rs └── api/ ├── Cargo.toml └── src/lib.rs
cli/Cargo.toml — depend on a workspace sibling:
[dependencies]
core = { path = "../core" }cargo build # build all cargo build -p cli # build specific package cargo test -p core # test specific package cargo run -p cli # run specific binary
Cargo.toml Dependencies
[dependencies] serde = "1" # version requirement serde = "^1.0.100" # compatible with 1.0.100+ serde = "~1.0.100" # patch updates only serde = "=1.0.100" # exact version serde = "*" # any version (avoid) # With features serde = { version = "1", features = ["derive"] } # Optional dependency (activate via feature flag) serde = { version = "1", optional = true } # From git rand = { git = "https://github.com/rust-random/rand" } rand = { git = "...", rev = "abc123" } rand = { git = "...", branch = "master" } rand = { git = "...", tag = "v0.8.5" } # From local path mylib = { path = "../mylib" } [dev-dependencies] # only for tests and examples criterion = "0.5" [build-dependencies] # only for build.rs cc = "1" [features] default = ["serde"] # active by default serde = ["dep:serde"] # feature named "serde" enabling dep:serde full = ["serde", "async"] async = ["tokio"]
Enabling features:
cargo build --features "serde async" cargo build --all-features cargo build --no-default-features cargo build --no-default-features --features "serde"
The Prelude
Rust automatically imports a set of commonly used items — the prelude — into every module:
// These are always in scope without `use`: // std::marker::{Copy, Send, Sized, Sync, Unpin} // std::ops::{Drop, Fn, FnMut, FnOnce} // std::mem::drop // std::boxed::Box // std::borrow::ToOwned // std::clone::Clone // std::cmp::{PartialEq, PartialOrd, Eq, Ord} // std::convert::{AsRef, AsMut, Into, From} // std::default::Default // std::iter::{Iterator, Extend, IntoIterator, DoubleEndedIterator, ExactSizeIterator} // std::option::Option::{self, Some, None} // std::result::Result::{self, Ok, Err} // std::string::{String, ToString} // std::vec::Vec
extern crate (Old Syntax)
Pre-Rust-2018, explicit extern crate was required. Now only needed for crates with a different name:
// 2015 edition (avoid) extern crate serde; // 2018+ edition — just use in Cargo.toml and import with `use`: use serde::{Serialize, Deserialize};
Module Organization Patterns
// lib.rs — public API surface, re-exports from internal modules pub mod error; pub mod config; // Re-export for ergonomic import at crate root pub use error::Error; pub use config::Config; // Internal module (pub(crate) to keep out of public API) pub(crate) mod internal;
Flat module tree (small projects):
src/ ├── lib.rs ├── error.rs ├── parser.rs └── types.rs
Domain-grouped module tree (larger projects):
src/
├── lib.rs
├── auth/
│ ├── mod.rs
│ ├── jwt.rs
│ └── oauth.rs
├── db/
│ ├── mod.rs
│ ├── schema.rs
│ └── queries.rs
└── api/
├── mod.rs
├── routes.rs
└── handlers.rsConditional Compilation
// Only compile this on Linux #[cfg(target_os = "linux")] fn linux_only() {} // Only compile in debug builds #[cfg(debug_assertions)] fn debug_check() { println!("debug mode"); } // Feature flag #[cfg(feature = "async")] pub mod async_impl; // Negate condition #[cfg(not(feature = "serde"))] fn no_serde_fallback() {} // Multiple conditions #[cfg(all(target_os = "linux", feature = "serde"))] fn linux_with_serde() {} #[cfg(any(target_os = "macos", target_os = "linux"))] fn unix_only() {} // cfg! macro — runtime check (actually compile-time) if cfg!(debug_assertions) { println!("debug build"); } // Conditionally include a file #[cfg(target_os = "windows")] include!("windows_impl.rs");