Черта ржавчины и ее реализация по умолчанию - PullRequest
0 голосов
/ 10 июня 2018

Написал черту, которая проверяет, является ли данное число (u16 или u32) четным или нет.

v1.0

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

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

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

fn main() {
    let x: u16 = 11;
    let y: u32 = 44;

    println!("x = {}, y = {}", x.is_even(), y.is_even());
}

Работает нормально.Но поскольку is_even повторяется для u16 и u32, он перемещается в черту как метод по умолчанию.

v2.0

trait EvenOdd {
    fn is_even(&self) -> bool {
        self % 2 == 0
    }
}

impl EvenOdd for u16 {
}

impl EvenOdd for u32 {
}

fn main() {
    let x: u16 = 11;
    let y: u32 = 44;

    println!("x = {}, y = {}", x.is_even(), y.is_even());
}

Это приводит к ошибке компилятора:

error[E0369]: binary operation `%` cannot be applied to type `&Self`
 --> trait_arithmetic_v2.rs:3:9
  |
3 |         self % 2 == 0
  |         ^^^^^^^^
  |
  = note: an implementation of `std::ops::Rem` might be missing for `&Self`

Попытка ограничения &self приводит к ошибке компилятора:

fn is_even<T: std::ops::Rem> (&self: T) -> bool
    self % 2 == 0
}

error: expected one of `)` or `,`, found `:`
 --> trait_arithmetic_v2.rs:2:44
  |
2 |         fn is_even<T: std::ops::Rem> (&self: T) -> bool {
  |                                            ^ expected one of `)` or `,` here

Единственный способ применить ограничение - изменить is_even api.

v3.0

use std::ops::Rem;

trait EvenOdd {
    fn is_even<T: Rem<Output = T> + PartialEq + From<u8>> (&self, other: T) -> bool {
        other % 2.into() == 0.into()
    }
}

И используйте это как x.is_even(x), что не естественно.Как исправить мой v2.0?Спасибо.

1 Ответ

0 голосов
/ 11 июня 2018

В v2.0 компилятор не знает тип, который вы пытаетесь применить арифметическую операцию, и trait EvenOdd: Rem не работает, потому что Rem занимает Self.

Этот коднесколько ограничен, но работает для вашего примера и является функциональным, потому что есть реализация по умолчанию impl From<u16> for u32.

use std::ops::Rem;

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

impl<T> EvenOdd for T
where
    T: Copy + From<u16> + PartialEq + Rem<Output=T>
{
    fn is_even(&self) -> bool {
        *self % From::from(2u16) == From::from(0u16)
    }
}

fn main() {
    let x: u16 = 11;
    let y: u32 = 44;

    println!("x = {}, y = {}", x.is_even(), y.is_even());
}
...