Таинственные противоречивые реализации - PullRequest
5 голосов
/ 08 марта 2020

Я пытался проверить свой код с фиксированным временем. поэтому я написал что-то вроде этого:

use std::time::{SystemTime, UNIX_EPOCH};

trait Clock {
    fn now(&self) -> SystemTime;
}

trait MixInClock {
    type Impl;
}

struct RealClock;
impl<T: MixInClock<Impl = RealClock>> Clock for T {
    fn now(&self) -> SystemTime {
        SystemTime::now()
    }
}

struct FakeClock;
impl <T: MixInClock<Impl = FakeClock>> Clock for T {
    fn now(&self) -> SystemTime {
        UNIX_EPOCH
    }
}

struct DIContainer;
impl MixInClock for DIContainer {
    type Impl = FakeClock;
}

Этот код выдает мне ошибку:


error[E0119]: conflicting implementations of trait `Clock`:
  --> src/lib.rs:19:1
   |
12 | impl<T: MixInClock<Impl = RealClock>> Clock for T {
   | ------------------------------------------------- first implementation here
...
19 | impl <T: MixInClock<Impl = FakeClock>> Clock for T {
   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation

Почему? Нет никакой возможности, что T реализует MixInClock<Impl = RealClock> и MixInClock<Impl = FakeClock> одновременно. верно?

https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=95e3647b30ae0e37c45ac18da495a3c5

Ответы [ 2 ]

2 голосов
/ 08 марта 2020

Вы столкнулись с давней проблемой с правилами согласованности Rust . Есть предложения, как решить эту проблему, но работа пока отложена. Цитировать Последний комментарий Йонаса Шивинка об ошибке :

Чтобы сообщить об этом: В 2016 году было предложено исправить RF C 1672 это, но было отложено до завершения интеграции с Chalk. Кроме того, в соответствии с rust-lang / rfcs # 1672 (комментарий) , разрешение этих типов impls позволит пользователям express взаимоисключающие черты, что является очень мощной функцией, которая требует более глубокого рассмотрения. языковой командой (следовательно, помечена как заблокированная на RF C).

0 голосов
/ 08 марта 2020

Хотя ответ Свена верен, что это проблема правил согласованности Rust, вы можете решить эту проблему, просто немного обобщив код. В общем, когда у вас есть два разных типа, которые должны иметь разное поведение, но похожий интерфейс, часто полезно создать для этого признак.

В этом случае вы можете создать признак для RealClock и FakeClock, который каждый может реализовать, и использовать это в вашей реализации generi c Clock вместо добавления поведения каждого непосредственно:

// Common interface for RealClock and FakeClock, implemented separated for each
trait ClockImpl {
    fn now() -> SystemTime;
}

impl ClockImpl for RealClock {
    fn now() -> SystemTime {
        SystemTime::now()
    }
}

impl ClockImpl for FakeClock {
    fn now() -> SystemTime {
        UNIX_EPOCH
    }
}

// MixInClock only needs to now that Self::Impl implements ClockImpl
trait MixInClock {
    type Impl: ClockImpl;
}

// We call the T::Impl::now() method for the specific behavior of RealClock and FakeClock
impl<T: MixInClock> Clock for T {
    fn now(&self) -> SystemTime {
        <T::Impl as ClockImpl>::now()
    }
}

Код на площадке

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...