Const trait bound
- Rust course
- Advanced
- Lesson 68/81
- 4 min
Use trait bounds with const generics.
Types and traits with const parameters
Types with const parameters can implement traits and be used in trait bounds. Since the size is part of the type, a size mismatch is a compile error; no runtime check is needed:
struct Vektor<const N: usize>([f64; N]);
impl<const N: usize> Vektor<N> {
fn nokta(&self, o: &Self) -> f64 {
self.0.iter().zip(o.0.iter()).map(|(a, b)| a * b).sum()
}
}
let a = Vektor([1.0, 2.0, 3.0]);
let b = Vektor([4.0, 5.0, 6.0]);
println!("{}", a.nokta(&b)); // 32
// a.nokta(&Vektor([1.0, 2.0])); // error: Vektor<3> expectedImplementing traits
A single trait implementation can be written for all sizes:
impl<const N: usize> Default for Vektor<N> {
fn default() -> Self {
Vektor([0.0; N])
}
}
impl<const N: usize> std::ops::Add for Vektor<N> {
type Output = Self;
fn add(self, o: Self) -> Self {
let mut t = [0.0; N];
for i in 0..N { t[i] = self.0[i] + o.0[i]; }
Vektor(t)
}
}Practice Dot product
Write the Vektor<const N: usize> type above and the nokta method. Print the dot product of Vektor([1.0, 2.0, 3.0]) and Vektor([4.0, 5.0, 6.0]).
Starter code
fn main() {
// buraya yaz
}Sample solution
struct Vektor<const N: usize>([f64; N]);
impl<const N: usize> Vektor<N> {
fn nokta(&self, o: &Self) -> f64 {
self.0.iter().zip(o.0.iter()).map(|(a, b)| a * b).sum()
}
}
fn main() {
let a = Vektor([1.0, 2.0, 3.0]);
let b = Vektor([4.0, 5.0, 6.0]);
println!("{}", a.nokta(&b));
}Expected output
32
Questions and answers
Review the lesson questions together with their answers. To test yourself, solve the lesson interactively.
1 How would the same error be caught with a <code>Vec<f64></code>-based vector?
- Only at runtime, by comparing lengths Correct answer
- At compile time
- It couldn't be
- By type checking
Explanation: Const generics move an invariant into the type system; the error is shown before the program runs.
2 For all sizes
impl____ Default for Vektor<N> {
fn default() -> Self {
Vektor([0.0; N])
}
}
impl<const N: usize> Default for Vektor<N> {
fn default() -> Self {
Vektor([0.0; N])
}
}
Explanation: The impl block must declare the const parameter too.
3 Expression and result
| Term | Meaning |
|---|---|
Vektor([1.0, 2.0, 3.0]).nokta(&b) |
32 |
Vektor<3> · Vektor<2> |
Compile error |
Vektor::<4>::default() |
[0.0; 4] |
Vektor<2> + Vektor<2> |
Vektor<2> |