Testing, Cargo, Functional Features
2026-09-08
anagram.rs if neededmove keyword says to move rather than borrowCopy data, results in a copyCopy data, makes a differenceClosures are syntactic sugar for:
struct type
Fn, FnMut, or FnOncestruct fieldsFn: Only borrows shared refs to capturesFnMut: Borrows mutable refs to capturesFnOnce: Moves data
FnOnceFnFnOnce is a trait, not a concrete type, so:
Can also use impl argument:
The next method
Some(item) if there is one availableNone if the collection is exhaustedfor loop consumes an iteratorIntoIterator for default iteratorVec)collect method collects iterator output
block
columns 7
lidx["idx"]
block:idx:6
i0["0"] i1["3"] i2["5"] i3["5"] i4["5"] i5["5"]
end
space:7
lnbr["nbr"]
block:nbr:6
n0["1"] n1["2"] n2["3"]
n3["6"] n4["7"] n5["*"]
end
style lidx stroke-width:0px,fill:none
style lnbr stroke-width:0px,fill:none
i0 --> n0
i1 --> n3
i2 --> n5
i3 --> n5
i4 --> n5
i5 --> n5
// Neighbors of node i are in neighbors[idx[i]..idx[i+1]]
struct CompressedSparseGraph {
neighbors: Vec<usize>,
idx: Vec<usize>
}
struct EdgeIterator<'a> {
g: &'a CompressedSparseGraph, // Graph reference
i: usize, // Current first node
k: usize // Offset of second node in neighbors
}
impl CompressedSparseGraph {
fn edges<'a>(&'a self) -> EdgeIterator<'a> {
EdgeIterator { g: &self, i: 0, k: 0 }
}
}
impl<'a> Iterator for EdgeIterator<'a> {
type Item = (usize,usize);
fn next(&mut self) -> Option<Self::Item> {
if self.k < self.g.neighbors.len() {
let result = (self.i, self.g.neighbors[self.k]);
self.k += 1;
if self.k >= self.g.idx[self.i+1] {
self.i += 1;
}
Some(result)
} else {
None
}
}
}
fn main() {
let idx = vec![0,1,2,2];
let neighbors = vec![1,2];
let g = CompressedSparseGraph{neighbors, idx};
for (i,j) in g.edges() {
println!("({i},{j})");
}
}for loopsfor uses iterators!size_hint if collectingfilter_map vs filter + map)cargo new # Start a new project
cargo fmt # Reformat to Rust standard
cargo doc # Build package documentation
cargo clean # Clean up directory
cargo add # Add external crate dependency to Cargo.toml
cargo build # Build software
cargo run # Re-build if needed and run
cargo clippy # Lints your code
cargo test # Run tests
cargo bench # Run benchmarks
cargo package # Build a package
cargo install # Install a package from Crates.io… and more – see the Cargo book!
Profiles let you alter compiler settings
Cargo.toml in [profile] tabledev, release, test, bench
dev corresponds to debug mode--release flag if you want your code to go fast!Build script is build.rs in package root
Makefile or something)rustc
cargo clippy runs a linter
cargo package creates a .crate file
p1_maxagram-0.1.0.cratecrate files!NB: Changed crate name to p1_maxagram in P1
cargo publish uploads a crate to a registry
cargo install installs things in cargo spacecargo-* can be a cargo commandcargo install cargo-llvm-cov to get cargo llvm-cov“Beware of bugs in the above code; I have only proved it correct, not tried it.”
— Don Knuth, 1977
Tests should initially fail
There are implications for P1.
Goal: Check functions, small data structures, etc
src tree#[cfg(test)] to only build on test#[test]tests#[test]assert! (condition and optional string)assert_eq!, assert_ne!#[should_panic(expected = "less than")]assert!(value.is_err()) to check recoverable errorsSome nice things about the Rust ecosystem:
cargo, rustc, rustdoc)cargoLanguage choice is never just about the language!