3

I have been trying to learn Rust through rust-koans but ran into a wall with the following trait koan:

// There is an alternate syntax for placing trait bounds on a function, the
// where clause. Let's revisit a previous example, this time using 'where'.
#[test]
fn where_clause() {
    let num_one: u16 = 3;
    let num_two: u16 = 4;

    trait IsEvenOrOdd {
        fn is_even(&self) -> bool;
    }

    impl IsEvenOrOdd for u16 {
        fn is_even(&self) -> bool {
            self % 2 == 0
        }
    }

    fn asserts<T>(x: T, y: T) {
        assert!(!x.is_even());
        assert!(y.is_even());
    }

    asserts(num_one, num_two);
}

It seems the goal is to complete this code by creating a generic version of the IsEvenOrOdd implementation. In this case the generic type should have two bounds, the remainder operator and the PartialEq operator. Because the remainder right side and equivalence right side are integers, I eventually wrote the following spaghetti code:

use std::ops::Rem;

impl<T> IsEvenOrOdd for T
where
    T: Rem<u16> + Rem,
    <T as Rem<u16>>::Output: PartialEq<u16>,
{
    fn is_even(&self) -> bool {
        self % 2 == 0
    }
}

Still - the code doesn't compile. It seems that since T is dereferenced I would need to add bounds to the dereferenced value, but I cannot find any example of how to do that.

error[E0369]: binary operation `%` cannot be applied to type `&T`
   --> src\koans/traits.rs:142:13
    |
142 |             self % 2 == 0
    |             ^^^^^^^^
    |
    = note: an implementation of `std::ops::Rem` might be missing for `&T`

In short: What would be the idiomatic Rust way to solve this koan?

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
devaj
  • 333
  • 2
  • 8
  • 4
    "It seems the goal is to complete this code by createing a generic version of the IsEvenOrOdd implementation." Is it? I would assume the goal is just to add a `where` clause so that the code compiles. – trent Dec 15 '18 at 18:36
  • Possible duplicate of [Wrong trait choosen based on type parameter](https://stackoverflow.com/questions/53125347/wrong-trait-choosen-based-on-type-parameter) – trent Dec 15 '18 at 19:26
  • I agree; to solve the koan, add `where T: IsEvenOrOdd` to `fn asserts`. – Shepmaster Dec 16 '18 at 01:15

1 Answers1

2

I think you may have misinterpreted the intention of this exercise. What you want is this:

fn main() {
    let num_one: u16 = 3;
    let num_two: u16 = 4;

    trait IsEvenOrOdd {
        fn is_even(&self) -> bool;
    }

    impl IsEvenOrOdd for u16 {
        fn is_even(&self) -> bool {
            self % 2 == 0
        }
    }

    fn asserts<T>(x: T, y: T)
        where T: IsEvenOrOdd {
        assert!(!x.is_even());
        assert!(y.is_even());
    }

    asserts(num_one, num_two);
}

How did I come to this conclusion? Trying to compile and run the original code you posted results in the following error:

error[E0599]: no method named `is_even` found for type `T` in the current scope
  --> src/main.rs:16:20
   |
16 |         assert!(!x.is_even());
   |                    ^^^^^^^
   |
   = help: items from traits can only be used if the trait is implemented and in scope
   = note: the following trait defines an item `is_even`, perhaps you need to implement it:
       candidate #1: `main::IsEvenOrOdd`

This error tells us that to call the is_even method, you must implement IsEvenOrOdd. The comments on the top of the example you posted say to use the where clause on a function. Adding the where clause to the function asserts solves your problem and completes the exercise.

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
Steampunkery
  • 3,839
  • 2
  • 19
  • 28