What HashSet does
A hash set of unique values, backed by the same machinery as HashMap.
As a struct, HashSet bundles related fields into a single named record with a known layout. Each field has a fixed type and offset, so the size of an instance is the sum of its field sizes plus alignment padding. Construction follows ordinary Rust ownership rules: each owned field must itself be constructed or moved before the struct is well-formed, and the compiler will refuse to leave any field uninitialised. The full canonical path is std::collections::HashSet; bring it into scope with use std::collections::HashSet; or refer to it by its full path.
When to use it
Use HashSet when you need fast membership checks and don't care about ordering. Reach for BTreeSet if you need sorted iteration or range queries.
Annotated examples
Set algebra: intersection of two HashSets
use std::collections::HashSet;
fn shared_tags(a: &HashSet<&str>, b: &HashSet<&str>) -> HashSet<&str> {
a.intersection(b).copied().collect()
}
fn main() {
let a: HashSet<_> = ["rust", "async", "web"].into_iter().collect();
let b: HashSet<_> = ["web", "crypto", "rust"].into_iter().collect();
let common = shared_tags(&a, &b);
assert_eq!(common.len(), 2);
}
HashSet exposes intersection, union, difference, and symmetric_difference as iterators — combine with collect() for a new set.
For deeper background, see the canonical Rust patterns reference for the broader context behind this section.
Deduplicating a Vec via FromIterator
use std::collections::HashSet;
fn unique<T: Eq + std::hash::Hash>(items: Vec<T>) -> Vec<T> {
items.into_iter().collect::<HashSet<_>>().into_iter().collect()
}
Round-tripping through HashSet is the shortest dedup recipe in safe Rust. Note that ordering is not preserved — use IndexSet from indexmap if you need stable order.
Common pitfalls
Iteration order of HashSet is randomised per process — never rely on it for serialisation or test assertions. Equality and hashing are linked: if two values compare equal they MUST hash equal, otherwise the set will silently behave incorrectly.
For deeper background, see an in-depth Rust idioms cheat sheet for the broader context behind this section.
Performance & threading notes
Stack-allocated by default. Heap allocation only happens if a field is itself heap-allocated (Vec, String, Box). Cloning copies every field; for read access pass by reference. Send / Sync are automatically derived if every field is Send / Sync.