Tired of manually counting array lengths and const generic arguments? Since Rust 1.89, you can write _ in const generic positions and let the compiler figure it out.
The annoyance
Whenever you work with arrays or const generics, you end up counting elements by hand:
1
2
3
4
5
6
7
8
9
10
| fn main() {
let rgb: [u8; 3] = [255, 128, 0];
let matrix: [[f64; 3]; 2] = [
[1.0, 0.0, 0.0],
[0.0, 1.0, 0.0],
];
assert_eq!(rgb.len(), 3);
assert_eq!(matrix.len(), 2);
}
|
Change the data, forget to update the length, and you get a compile error — or worse, you waste time counting elements that the compiler already knows.
Enter _ for const generics
Now you can replace const generic arguments with _ wherever the compiler can infer the value:
1
2
3
4
5
6
7
8
9
10
11
| fn main() {
let rgb: [u8; _] = [255, 128, 0];
let matrix: [[f64; _]; _] = [
[1.0, 0.0, 0.0],
[0.0, 1.0, 0.0],
];
assert_eq!(rgb.len(), 3);
assert_eq!(matrix.len(), 2);
assert_eq!(matrix[0].len(), 3);
}
|
The compiler sees 3 elements and fills in the 3 for you. Add a fourth element tomorrow, and the type updates automatically — no manual bookkeeping.
Array repeat expressions
The _ also works in repeat expressions, so you can define how many times to repeat without hardcoding the count:
1
2
3
4
5
6
7
8
9
10
11
| fn zeros<const N: usize>() -> [f64; N] {
[0.0; _]
}
fn main() {
let small: [f64; 3] = zeros();
let big: [f64; 8] = zeros();
assert_eq!(small, [0.0, 0.0, 0.0]);
assert_eq!(big.len(), 8);
}
|
Inside zeros(), [0.0; _] infers the repeat count from the return type’s N. No need to write [0.0; N] — though you still can.
Works with your own const generics too
Any function with const generic parameters can benefit:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
| fn chunk_sum<const N: usize>(arr: [i32; N]) -> i32 {
arr.iter().sum()
}
fn main() {
// The compiler infers N = 4 from the array literal
let total = chunk_sum([10, 20, 30, 40]);
assert_eq!(total, 100);
// Explicit _ works too when you want to be clear about inference
let arr: [i32; _] = [1, 2, 3, 4, 5];
let total = chunk_sum(arr);
assert_eq!(total, 15);
}
|
Where you can’t use _
One important restriction: inferred const generics are only allowed in expressions, not in item signatures. You can’t write this:
1
2
| // This does NOT compile — _ not allowed in function signatures
// fn make_pairs() -> [(&str, i32); _] { ... }
|
The compiler needs concrete types in signatures. Use _ inside function bodies and let bindings where the compiler has enough context to infer.
A small quality-of-life win that removes one more source of busywork. Next time you’re stacking array literals, let the compiler do the counting.