Использование impl Trait внутри другого типа, который поддерживает дженерики - PullRequest
0 голосов
/ 01 августа 2020

У меня есть следующая черта publi c

pub trait UIElement {
    /// Is this UIElement a child of any other UIElement?
    fn parent<T: UIElement>(&self) -> Option<T>;

    /// Where to position
    /// TODO: Determine recursivly by checking the position of
    /// its parents.
    fn area(&self) -> Area;

    /// Should this UIElement be visible?
    fn visible(&self) -> bool;

    /// Is this UIElement actually visible?
    /// A UIElement can only be visible, if the parent (e.g. a container)
    /// is also visible (and its parent and so on resursively).
    fn actually_visible(&self) -> bool {
        let parent_visible: bool = if let Some(parent) = self.parent() {
            parent.actually_visible()
        }else { true };

        parent_visible && self.visible()
    }
}

actually_visible() должна возвращать только истину, если сама visible(), а также предыдущий родительский actually_visible() рекурсивный.

Когда я создавал метод parent(), я не мог просто использовать Option<impl UIElement> или Option<Self> (Self, вероятно, работает только для реальных структур, если я не ошибаюсь) в качестве возвращаемого типа. Тем не менее, синтаксис, который я выбрал, в основном должен быть версией Option<impl UIElement> без сахара. Используя это, компилятор, по крайней мере, больше не жалуется. (Хотя я все еще немного раздражен, но вопрос не в этом).

Проблема теперь в actually_visible(). Он не может сделать вывод о типе родителя при попытке разрешить из него actually_visible().

error[E0282]: type annotations needed
error[E0282]: type annotations needed
  --> src/ui.rs:40:13
   |
40 |             parent.actually_visible()
   |             ^^^^^^ cannot infer type
   |
   = note: type must be known at this point
help: consider specifying the type argument in the method call
   |
39 |         let parent_visible: bool = if let Some(parent) = self.parent::<T>() {
   |                                                                     ^^^^^

Как я могу заставить это работать?

PS: Я уже изучал некоторые другие решения. Хотя Есть ли способ сигнализировать, что тип трейта impl также реализует дополнительные трейты? У есть очень похожий вопрос, который, похоже, не работает для меня. Может у компилятора ржавчины проблемы / ограничения с рекурсией?

1 Ответ

0 голосов
/ 01 августа 2020

Похоже, что единственное место, где вы пытаетесь использовать дженерики, находится в этой строке:

fn parent<T: UIElement>(&self) -> Option<T>;

В этом нет необходимости, поскольку Rust уже знает, что фактический тип, с которым будут работать, будет более конкретным тип, который реализует UIElement, и поэтому использование generi c здесь, похоже, не требуется.

С учетом сказанного, поскольку Rust не знает заранее размер фактического объекта, который будет использоваться (поскольку он может варьироваться), вам нужно будет полагаться на кучу для хранения таких объектов.

Поэтому я заменил T в возвращаемом типе на

Box<dyn UIElement>

вот так ...

fn parent(&self) -> Option<Box<dyn UIElement>>;

После добавления определения для Area

pub struct Area
{

}

я смог скомпилировать ваш код (хотя какой использовать для "Area" - решать вам).

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