【问题标题】:"overflow evaluating the requirement" when trying to defer associated types尝试延迟关联类型时“溢出评估需求”
【发布时间】:2019-09-15 09:21:45
【问题描述】:

在 Rust 中,我试图延迟类型以测试解耦的高级逻辑。理想情况下,我想将最小关系规则表示为关联类型的类型约束。在这个简化的示例中,错误类型之间唯一关键的关系是它们的值可以从低级转换为高级。

虽然这些关系似乎应该终止,但编译器会出现“溢出评估需求”的错误。我无法确定我的类型函数是否有缺陷,或者我是否遇到了 Rust 中已知或未知的限制。示例:

pub trait CapabilityA {
    type Error;
    fn perform_a(&self) -> Result<String, Self::Error>;
}

pub trait CapabilityB {
    type Error;
    fn perform_b(&self, a: &str) -> Result<(), Self::Error>;
}

pub trait Application {
    type Error;
    fn go(&self) -> Result<(), Self::Error>;
}

impl<T> Application for T
where
    T: CapabilityA + CapabilityB,
    <T as Application>::Error: From<<T as CapabilityA>::Error> + From<<T as CapabilityB>::Error>,
{
    fn go(&self) -> Result<(), Self::Error> {
        let a = self.perform_a()?;
        let b = self.perform_b(&a)?;
        Ok(b)
    }
}

编译器响应:

error[E0275]: overflow evaluating the requirement `<Self as Application>::Error`
  --> src/lib.rs:11:1
   |
11 | / pub trait Application {
12 | |     type Error;
13 | |     fn go(&self) -> Result<(), Self::Error>;
14 | | }
   | |_^
   |
   = note: required because of the requirements on the impl of `Application` for `Self`

【问题讨论】:

    标签: rust


    【解决方案1】:

    一个更简单的例子reproducing the same error是:

    pub trait Foo {}
    
    pub trait Application {
        type Error;
    }
    
    impl<T> Application for T where <T as Application>::Error: Foo {}
    

    您对Application 的定义是递归的。要知道Ts 实现了什么Application,您需要评估&lt;T as Application&gt;,这需要编译器知道Ts 实现了Application,等等。

    Application的实现中,你要选择一个具体的Error,例如here with String

    impl<T> Application for T
    where
        T: CapabilityA + CapabilityB,
        String: From<<T as CapabilityA>::Error>,
        String: From<<T as CapabilityB>::Error>,
    {
        type Error = String;
    
        fn go(&self) -> Result<(), Self::Error> {
            let a = self.perform_a()?;
            let b = self.perform_b(&a)?;
            Ok(b)
        }
    }
    

    【讨论】:

    • 谢谢@mcarton。我制作了一个以这种方式工作的版本,但我希望可以在应用程序程序集或接线模块中进行错误(和其他一些)定义 - 使业务逻辑可单独测试。
    • 我不明白的是为什么编译器在发现 T as Application 是正在定义的内容时不知道终止。是因为某种原因它不能,还是只是没有以这种方式实现?
    • @aztecrex 编译器之前可以捕获错误,但有什么意义呢?代码仍然无法编译,因为您实际上从未在任何地方设置Error,只是对其设置了一些约束,并且编译器中已经存在防止无限递归边界的逻辑,即“溢出评估需求”错误你得到了。鉴于这些情况,检测这种特殊情况没有多大意义。
    • 未捕获错误。终止我的意思是停止递归。似乎有足够的信息让编译器成功完成边界计算而不会出错
    • 但是没有足够的信息!您从未真正指定Error 的类型。即使你忽略了界限,你也错过了type Error =
    【解决方案2】:

    基于@mcarton 的回答及其讨论,编译并表达我意图的替代方案是:

    pub trait CapabilityA {
        type Error;
        fn perform_a(&self) -> Result<String, Self::Error>;
    }
    
    pub trait CapabilityB {
        type Error;
        fn perform_b(&self, a: &str) -> Result<(), Self::Error>;
    }
    
    
    pub trait HasApplicationError: {
        type Error;
    }
    
    pub trait Application : HasApplicationError {
        fn go(&self) -> Result<(), Self::Error>;
    }
    
    impl<T> Application for T
    where
        T: CapabilityA + CapabilityB + HasApplicationError,
        <T as HasApplicationError>::Error: From<<T as CapabilityA>::Error> + From<<T as CapabilityB>::Error>,
    {
        fn go(&self) -> Result<(), Self::Error> {
            let a = self.perform_a()?;
            let b = self.perform_b(&a)?;
            Ok(b)
        }
    }
    
    

    代码比我希望的要多一些,但看起来还不错。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-08-12
      • 1970-01-01
      • 2021-05-17
      • 2021-08-13
      • 1970-01-01
      • 1970-01-01
      • 2019-06-19
      • 1970-01-01
      相关资源
      最近更新 更多