Rust / Basic / Lesson 6
Collections and validated input
Store owned sequences and keyed values, distinguish parsing from domain validation, and avoid depending on collection iteration order that is not promised.
On this page
Lesson goals
- Use Vec, HashMap, and BTreeMap according to required operations.
- Validate indices and explain size versus capacity.
- Parse complete trimmed input and enforce an application range.
Length counts values, capacity counts reserved space
Vec<T> owns a growable contiguous sequence of T values. len reports initialized elements; capacity describes allocation available before growth needs more space. with_capacity or reserve does not create those elements. push appends a value, while indexing requires a valid element position and may panic outside the length. get returns Option and is useful at uncertain boundaries. Borrowing rules prevent retaining an element reference across a mutation that could invalidate access. Use the public container interface rather than constructing pointers into spare capacity in ordinary application code.
Read existing elements without consuming them
The first example reserves space, appends a fourth score, and sums through shared iteration. iter yields shared references, and copied converts Copy integers into values for sum. The explicit u32 result type selects the accumulator type. These inputs keep the total representable; a production aggregate must still choose its overflow policy. After shared iteration ends, the vector remains owned and usable. Capacity is intentionally not printed because the exact allocated amount is not part of the behavioral contract. A compact iterator pipeline does not remove numeric domain obligations.
fn main() {
let mut scores = Vec::with_capacity(8);
scores.extend([2u32, 4, 6]);
scores.push(8);
let total: u32 = scores.iter().copied().sum();
println!("{} {total}", scores.len());
}
4 20
The vector has four elements totaling twenty. Summing through iter does not consume the owning vector.
Choose lookup and ordering deliberately
HashMap stores key/value associations with expected efficient lookup, but its traversal order is not a stable reporting order. BTreeMap provides key-ordered traversal with different complexity and storage tradeoffs. Do not print a whole HashMap and promise a particular key order in an example. get borrows a value, insert can replace an existing value, and entry supports update-or-insert without a separate logical lookup sequence. A map owns its ordinary String keys unless you deliberately design borrowed keys with lifetimes. For reports, choose ordered storage or sort a separate collected key list.
Parse first, validate second
Real console input can be read into an owned String with read_line, whose I/O result also needs handling. This lesson uses a synthetic line so the complete program has deterministic output. trim applies a deliberate whitespace policy, parse attempts a whole-string integer conversion, and a guard enforces zero through one hundred. A successful parse of two hundred is still a domain failure. A malformed suffix does not become a valid count merely because it begins with digits. Keep I/O failure, parse failure, and application rejection distinguishable when callers need different recovery behavior.
fn main() {
let line = " 12 ";
match line.trim().parse::<u32>() {
Ok(count) if count <= 100 => println!("accepted {count}"),
Ok(_) => println!("out of range"),
Err(_) => println!("invalid integer"),
}
}
accepted 12
Whitespace is removed explicitly, twelve parses as u32, and the bounded-domain guard accepts it.
Validate size as well as value
Untrusted input can consume too much memory even when every element is memory-safe. Limit record counts and line sizes according to the application instead of blindly collecting an unbounded source. Validate indices before access and consider get for expected absence. Decide whether duplicate keys replace values, accumulate totals, or cause rejection. When retrying console input, clear or replace the previous buffer intentionally so old text is not appended accidentally. Test empty collections, missing keys, duplicate records, malformed lines, and maximum permitted counts. These are product rules rather than facts inferred by the type checker.
Common errors and fixes
A reserved vector is indexed before elements exist.
- Why it happens
- Capacity was confused with length.
- How to fix it
- Push or resize before element access.
- Prevent it next time
- Validate indices against len, never capacity.
A report changes key order between runs.
- Why it happens
- HashMap order was treated as guaranteed.
- How to fix it
- Use BTreeMap or sort report keys.
- Prevent it next time
- Separate lookup requirements from presentation ordering.
Repeated input contains the previous line.
- Why it happens
- read_line appended to an uncleared String buffer.
- How to fix it
- Clear the buffer before each new read.
- Prevent it next time
- Make buffer reuse part of the input-loop contract.
Check your understanding
1. Predict the input example for "101", "12x", and "-1". Explain which layer rejects each line.
Show worked solution
101 parses as u32 but prints out of range. 12x fails whole-integer parsing and prints invalid integer. -1 also fails conversion to unsigned u32 and prints invalid integer. Trimming changes surrounding whitespace only; it does not remove an unwanted suffix or reinterpret a negative sign as a valid nonnegative count.
2. Count red, blue, red in a map and produce a deterministic alphabetical report. State the final counts and an appropriate container choice.
Show worked solution
Use BTreeMap<String, u32> and increment the value from entry(color).or_insert(0), with a suitable overflow policy for large inputs. The counts are blue one and red two, and key-order iteration reports blue before red. A HashMap can hold the same counts, but its direct iteration order must not define the expected report.
Key takeaways
- Length and capacity describe different resources.
- Choose explicit input, duplicate, and ordering policies.
- Memory-safe collections still need domain and resource limits.