尝试推迟关联类型时“评估需求的溢出”

时间:2019-04-25 21:22:54

标签: rust

在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`

2 个答案:

答案 0 :(得分:3)

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

pub trait Foo {}

pub trait Application {
    type Error;
}

impl<T> Application for T where <T as Application>::Error: Foo {}

您对Application的定义是递归的。要了解T的实现方式Application,您需要评估<T as Application>,这要求编译器知道T的实现方式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)
    }
}

答案 1 :(得分:0)

根据@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)
    }
}

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