66. Inferred Const Generics — Let the Compiler Count For You

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.

← Previous 65. Precise Capturing — Stop impl Trait From Borrowing Too Much Next → 67. Box::leak — Turn Owned Data Into a Static Reference