We can't find the internet
Attempting to reconnect
Something went wrong!
Attempting to reconnect
← Generics and Traits step 5 of 24
A generic Stack, and conditional impl blocks
Types can be generic too, not just functions:
pub struct Stack<T> {
items: Vec<T>,
}
Stack<i64> and Stack<String> are two entirely separate types, produced by
the same monomorphisation machinery you met with generic functions. Neither
can be assigned to the other.
The interesting part is the impl block. You will write two:
impl<T> Stack<T> { ... } // available for every T
impl<T: Display> Stack<T> { ... } // available only when T: Display
Read impl<T> Stack<T> carefully. The first <T> declares a type parameter
for the block; the second is applying Stack to it. Two different jobs, same
letter — this is the single most common early confusion. impl Stack<i64> (no
declaration) is also legal and adds methods to that one concrete instantiation
only.
The second block is a conditional API: render exists on Stack<i64>
because i64: Display, and simply does not exist on a Stack<SomeOpaqueThing>.
This is exactly how the standard library is built —
Option<T>::unwrap_or_default only exists when T: Default, Vec<T>::dedup
only when T: PartialEq. When you notice a std method “missing”, the usual
reason is a bound you have not satisfied, not a gap in the library.
Your task
pub struct Stack<T> // new, push, pop, len, is_empty
impl<T: Display> Stack<T> // render
pub fn run(ops: Vec<(String, i64)>) -> Vec<String>
run drives a Stack<i64> through a list of (op, arg) pairs and returns one
line per op:
| op | effect | output |
|---|---|---|
push |
push arg |
len=2 |
pop |
pop |
pop=7, pop=none |
render |
— |
[5,-3] |
empty |
— |
empty=true |
| anything else | — |
? |
render joins the elements bottom-to-top with , and run wraps that in
square brackets. An empty stack renders as [].
Two clippy gates, and why they are the lesson
The starter compiles. It still fails, twice:
error: you should consider adding a `Default` implementation for `Stack<T>`
error: struct `Stack` has a public `len` method, but no `is_empty` method
Both are default-on (new_without_default, len_without_is_empty) and both
fire only because the type is pub. On a private helper struct clippy
stays quiet. That asymmetry is deliberate: these are API-design rules, and a
type nobody else can name has no API to design. Since you are shipping Stack
as public, you owe callers both fixes.
Write Default by hand. #[derive(Default)] on Stack<T> looks
equivalent and is not: derive adds a T: Default bound, so
Stack::<NotDefault>::default() would stop compiling even though an empty
stack needs no T value at all. A hand-written
impl<T> Default for Stack<T> { fn default() -> Self { Self::new() } } has no
such bound. This is your first sighting of a trap that gets a whole article
later in the track: #[derive] lies about its bounds.
One more error worth causing
Delete the items field and leave pub struct Stack<T>;. You get:
error[E0392]: type parameter `T` is never used
Rust insists every parameter be used, because an unused one would leave
variance and drop behaviour undefined. The escape hatch when you genuinely
want a phantom parameter is std::marker::PhantomData<T>, a zero-sized field
that “uses” T without storing one.
Remember the grade is compile + tests + clippy -D warnings.
Stuck?
Rust reference solution
Sign in to attempt this problem and reveal the reference solution.