«переполнение при оценке требования» при попытке отложить связанные типы - PullRequest
0 голосов
/ 26 апреля 2019

В 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 ]

3 голосов
/ 26 апреля 2019

Более простой пример , воспроизводящий ту же ошибку :

pub trait Foo {}

pub trait Application {
    type Error;
}

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

Ваше определение Application рекурсивно. Чтобы узнать, что T s реализует Application, необходимо оценить <T as Application>, для чего требуется, чтобы компилятор знал, что T s реализует Application и т. Д.

В реализации Application вам нужно выбрать бетон Error, например здесь с 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)
    }
}
0 голосов
/ 08 мая 2019

Основываясь на ответе @ 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)
    }
}

Это немного больше кода, чем я ожидал, но, похоже, все в порядке.

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