In this lesson, you will learn how to use const generics to implement traits for arrays of any size, allowing your custom logic to scale across different array lengths.
The Challenge of Array Lengths
In Rust, [i32; 3] and [i32; 5] are distinct types. Before const generics, if you wanted to implement a trait for an array, you would have to write separate implementations for every possible length (e.g., one for size 1, one for size 2, etc.). Const generics allow us to treat the size of the array as a parameter N, effectively writing one implementation for all arrays of a specific type.
Implementing a Trait for Generic Arrays
Suppose you want to define a Summarizable trait that calculates the sum of any array containing integers. Instead of hardcoding the length, you use the const N: usize syntax:
trait Summarizable {
fn sum_elements(&self) -> i32;
}
impl<const N: usize> Summarizable for [i32; N] {
fn sum_elements(&self) -> i32 {
self.iter().sum()
}
}
fn main() {
let small = [1, 2, 3];
let large = [10, 20, 30, 40, 50];
println!("{}", small.sum_elements()); // Works!
println!("{}", large.sum_elements()); // Also works!
}
Why This Matters
By using <const N: usize>, you are telling the compiler: "This implementation applies to any array of i32 elements, regardless of whether it contains three, five, or one hundred items." This reduces code duplication significantly.
You can also add trait bounds to the generic type if you want to support more than just i32. For example, using [T; N] where T: std::ops::Add<Output = T> + Copy would allow your trait to work with any numeric type that supports addition. This flexibility is the foundation of building robust, library-grade data structures in Rust.
Key Takeaway: By using const generics (const N: usize), you can implement traits for all arrays of a specific type at once, avoiding the need to manually define implementations for every individual array length.