Convince the compiler that an integer implements Eq + Rem + fmt


#1
pub mod fb
{
    pub enum Term <T: ::std::cmp::Eq + ::std::ops::Rem + ::std::fmt::Display> 
    {
        Num(T),
        Txt(::std::borrow::Cow<'static, str>)
    }

    pub fn nth<T : ::std::cmp::Eq + ::std::ops::Rem + ::std::fmt::Display>(i: T) -> self::Term<T>
    {
        match (i % 3, i % 5) 
        {
            (0, 0) => Term::Txt(::std::borrow::Cow::from("FizzBuzz")),
            (0, _) => Term::Txt(::std::borrow::Cow::from("Fizz")),
            (_, 0) => Term::Txt(::std::borrow::Cow::from("Buzz")),
            _      => Term::Num(i)
        }
    }
}

fn main()
{
    for i in 1 ..= 100 
    {
        println!("{}", fb::nth(i));
    }
}

In the implementation of my fizzbuzz, I have used raw 0, 3 and 5 (which are {integers}). Thus the compiler complains:

error[E0308]: mismatched types  --> src/main.rs:11:20
   |
11 |         match (i % 3, i % 5)
   |                    ^ expected type parameter, found integral variable
   |
   = note: expected type `T`
              found type `{integer}`

Now how can I convince rustc that 3, 5 and 0 implements traits described by T?


#2

T is not a list of traits, it’s a type. The problem is that T is any type that implements those traits. It’s not even necessarily an integer.

You cannot mix literals and generics; you need to either not use generics, or find a method that converts to T from some specific integer type ({integer} is not a type; it’s a literal before it has a concrete type). Or require methods or associated constants that can construct the values you need.

Edit: Or require that T implements Rem for a RHS type of a specific integer type.


#3

play is one way to do it.


#4

Also, if you use the num crate, you can remove some of the std::ops boilerplate: play.