We can't find the internet
Attempting to reconnect
Something went wrong!
Attempting to reconnect
← Performance and Data Layout step 19 of 20
Const generics: moving a size from runtime to compile time
This is the cleanest demonstration in the language of a single idea: information moved earlier is speed.
A sliding-window sum over a million u64s, measured on this toolchain:
| window width | time |
|---|---|
const generic N = 4 |
0.304 ms |
runtime usize width 4 |
1.305 ms |
4.3×, from identical arithmetic. The only difference is that in the first case the compiler knew the trip count, so it could unroll the inner loop, keep the four accumulators in registers, drop the loop counter entirely, and fold the bounds checks against a constant.
What a const generic is
pub fn moving_average<const W: usize>(v: &[f64]) -> Vec<f64>
W is a value parameter, not a type parameter. Calling
moving_average::<4>(&v) stamps out a copy of the function with W replaced
by the literal 4 everywhere it appears — the same monomorphisation machinery
as type generics, applied to a number.
Stable const generics accept integers, bool and char and nothing else.
The error every learner hits in the first five minutes
fn f<const N: usize>() -> [u8; N + 1] { ... }
error: generic parameters may not be used in const operations
help: const parameters may only be used as standalone arguments here, i.e. `N`
Note what is missing: there is no error number. rustc --explain has
nothing to tell you. This is one of the diagnostics you have to read rather
than look up, and the starter for this problem puts it in front of you
deliberately.
The rule is that N may appear as itself, but not inside an expression.
[0.0; N] is fine; [0.0; N + 1] is not. Const-generic expressions
(generic_const_exprs) remain unstable in 2026 — do not design around
them. The workarounds are to take a second const parameter for the derived
size, or to return a Vec.
Learners meet this immediately and conclude const generics are broken. They are not; they are simply smaller than you expected.
What to write
pub fn moving_average<const W: usize>(v: &[f64]) -> Vec<f64>
pub fn dispatch_window(v: &[f64], w: usize) -> Vec<f64>
moving_average returns one value per window of width W, in order:
output length is v.len() - W + 1, and each output is the sum of the window
accumulated from 0.0 left to right, divided by W. That order is part of
the specification — floating-point addition is not associative.
If W is 0, or longer than the input, return an empty vector.
dispatch_window is the bridge from a runtime width to a compile-time one:
match w against 2, 4, 8 and 16, call the const-generic version for
each, and fall back to an ordinary runtime-width loop for anything else. This
is how real code gets the win — you pay four monomorphisations for the widths
that matter and keep a general path for the rest.
The trick that makes the inner loop fast
let fixed: &[f64; W] = window.try_into().unwrap();
v.windows(W) yields &[f64] — a slice with a runtime length, which gives
the optimiser nothing. Converting it to a &[f64; W] hands back the constant:
now the loop over fixed has a known trip count, unrolls, and needs no bounds
checks at all. The try_into can never fail here, and it compiles to nothing.
Two more things worth knowing
Type-vs-const ambiguity. In Foo<N>, if a type named N is in scope,
Rust resolves N as that type, not as your const parameter. Foo<{ N }>
forces the const interpretation. It is rare and it is baffling when it
happens.
Const generics multiply code size faster than type generics. Every
distinct N is a separate monomorphisation, and unlike types there is no
natural limit on how many a caller might use. Four widths is a design
decision, not an accident — a match over sixteen would quadruple the code
for diminishing returns.
Errors and lints
The uncoded error above; E0770 (a const parameter’s type may not depend
on another generic parameter); E0401, E0747 (a type and a const argument
swapped), E0308. Lints: needless_range_loop, manual_memcpy,
large_const_arrays, and missing_const_for_fn (pedantic — a function that
could be const fn, which is the next item’s subject).
Remember the grade is compile + tests + clippy -D warnings.
Stuck?
Rust reference solution
Sign in to attempt this problem and reveal the reference solution.