【问题标题】:Mysterious conflicting implementations神秘的冲突实现
【发布时间】:2020-06-20 07:26:13
【问题描述】:

我试图用固定的时间测试我的代码。所以我写了这样的东西:

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&lt;Impl = RealClock&gt;MixInClock&lt;Impl = FakeClock&gt;。对吧?

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

【问题讨论】:

    标签: rust


    【解决方案1】:

    您遇到了long-standing issue with Rust's coherence rules。有一些建议如何解决这个问题,但目前这项工作已被推迟。引用Jonas Schievink's most recent comment on the bug:

    对此进行更新:2016 年,RFC 1672 被提议解决此问题,但被推迟到完成 Chalk 集成。此外,根据rust-lang/rfcs#1672 (comment),允许这些类型的 impl 将允许用户表达相互排斥的特征,这是一个非常强大的功能,需要语言团队更深入地考虑(因此在 RFC 上也标记为被阻止) .

    【讨论】:

      【解决方案2】:

      虽然 Sven 的回答是正确的,但这是 Rust 的连贯性规则的问题,您可以通过稍微概括您的代码来解决这个问题。实际上,当您有两种不同的类型应该具有不同的行为但具有相似的接口时,为此创建一个特征通常很有用。

      在这种情况下,您可以为 RealClockFakeClock 创建一个每个都可以实现的特征,并在您的通用 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()
          }
      }
      

      Code in playground

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2023-02-07
        • 1970-01-01
        • 1970-01-01
        • 2020-11-04
        • 2021-08-16
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多