CodeBlanks Logo Icon CodeBlanks

Const trait bound

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> expected

Implementing 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

main.rs
fn main() {
    // buraya yaz
}

Sample solution

main.rs
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&lt;f64&gt;</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

Question
impl____ Default for Vektor<N> {
    fn default() -> Self {
        Vektor([0.0; N])
    }
}
Answer
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>

All lessons in Advanced