Search code examples
rusttraits

Associated const to a trait in Rust not working as described in the tutorial


I am trying to execute the same code as described here

(Page ~448)

Playground

But when I try to execute this sample I get:

error[E0038]: the trait `Float` cannot be made into an object


--> src\main.rs:35:25
   |
35 |     let fibonacci_of_3: dyn Float = fibonacci(3);
   |                         ^^^^^^^^^ `Float` cannot be made into an object
   |
   = help: consider moving `ZERO` to another trait
   = help: consider moving `ONE` to another trait
note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
  --> src\maths.rs:4:11
   |
3  | pub trait Float {
   |           ----- this trait cannot be made into an object...
4  |     const ZERO: Self;
   |           ^^^^ ...because it contains this associated `const`
5  |     const ONE: Self;
   |           ^^^ ...because it contains this associated `const`

Here is the Fibonacci function:

pub fn fibonacci<T: Float + Add<Output=T>>(n: usize) -> T {
    match n {
        0 => T::ZERO,
        1 => T::ONE,
        n => fibonacci::<T>(n - 1) + fibonacci::<T>(n - 2),
    }
}

About the dyn, without it I get:

error[E0782]: trait objects must include the `dyn` keyword
  --> src\main.rs:34:25
   |
34 |     let fibonacci_of_3: Float = fibonacci(3);
   |                         ^^^^^
   |
help: add `dyn` keyword before this trait
   |
34 |     let fibonacci_of_3: dyn Float = fibonacci(3);
   |                         +++

Is the information outdated or am I doing something wrong?, in paper makes sense.

Regards

~M


Solution

  • You need to specify the types (not the trait itself) you want to use:

    use std::ops::Add;
    
    trait Float {
        const ZERO: Self;
        const ONE: Self;
    }
    
    impl Float for f32 {
        const ZERO: f32 = 0.0;
        const ONE: f32 = 1.0;
    }
    
    impl Float for f64 {
        const ZERO: f64 = 0.0;
        const ONE: f64 = 1.0;
    }
    
    fn fibonacci<T: Float + Add<Output=T>>(n: usize) -> T {
        match n {
            0 => T::ZERO,
            1 => T::ONE,
            n => fibonacci::<T>(n - 1) + fibonacci::<T>(n - 2),
        }
    }
    
    fn main() {
       let fibonacci_of_3: f32 = fibonacci::<f32>(3);
    }
    

    Playground

    Notice that you can not use dyn Float. The compiler do not know how to build the vtable for that trait, as it do not have any methods at all.