Как я могу преобразовать объект черты итератора конкретных типов в объект черты итератора объектов черты? - PullRequest
1 голос
/ 07 июня 2019

У меня есть черта, которая содержит функцию для возврата итератора по ссылкам на другую черту, например:

pub trait ParentInterface {
    fn children<'a>(&'a self) -> Box<dyn Iterator<Item = &'a ChildInterface>>;
}

pub trait ChildInterface {
    fn some_method(&self) -> bool;
}

Как можно вернуть итератор правильного типа при реализации этой черты для конкретного типа, который хранит вектор конкретных значений?

pub struct ConcreteParent {
    my_children: Vec<ConcreteChild>,
}

pub struct ConcreteChild {
    my_value: bool,
}

impl ParentInterface for ConcreteParent {
    fn children<'a>(&'a self) -> Box<dyn Iterator<Item = &'a ChildInterface>> {
        Box::new(self.my_children.iter()) // Compiler error!
    }
}

impl ChildInterface for ConcreteChild {
    fn some_method(&self) -> bool {
        self.my_value
    }
}

Приведенный выше пример выдает ошибку компилятора для Rust 2018:

error[E0271]: type mismatch resolving `<std::slice::Iter<'_, ConcreteChild> as std::iter::Iterator>::Item == &dyn ChildInterface`
  --> src/lib.rs:19:9
   |
19 |         Box::new(self.my_children.iter()) // Compiler error!
   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected struct `ConcreteChild`, found trait ChildInterface
   |
   = note: expected type `&ConcreteChild`
              found type `&dyn ChildInterface`
   = note: required for the cast to the object type `dyn std::iter::Iterator<Item = &dyn ChildInterface>`

Я предполагаю, что my_children.iter() возвращает итератор с неправильным типом Item (конкретный тип вместо типа черты) - как это можно решить?

1 Ответ

2 голосов
/ 07 июня 2019

По умолчанию объект черты ограничен 'static. Вы должны указать время жизни 'a, и тогда вы сможете правильно отобразить итератор ( source ):

pub trait ParentInterface {
    fn children<'a>(&'a self) -> Box<dyn Iterator<Item = &'a dyn ChildInterface> + 'a>;
}

pub trait ChildInterface {
    fn some_method(&self) -> bool;
}

pub struct ConcreteParent {
    my_children: Vec<ConcreteChild>,
}

pub struct ConcreteChild {
    my_value: bool,
}

impl ParentInterface for ConcreteParent {
    fn children<'a>(&'a self) -> Box<dyn Iterator<Item = &'a dyn ChildInterface> + 'a> {
        Box::new(self.my_children.iter().map(|c| c as &'a dyn ChildInterface))
    }
}

impl ChildInterface for ConcreteChild {
    fn some_method(&self) -> bool {
        self.my_value
    }
}

Обратите внимание на изменения:

  • Ссылочные границы итератора 'a, как и элементы:

    dyn Iterator</*...*/> + 'a
    
  • Каждый конкретный тип сопоставляется с объектом черты:

    .map(|c| c as &'a dyn ChildInterface)
    

    Обратите внимание, что вы можете упростить систему обозначений, чтобы сделать вывод: .map(|c| c as _)

Вы можете еще больше упростить, используя время жизни '_:

pub trait ParentInterface {
    fn children(&self) -> Box<dyn Iterator<Item = &dyn ChildInterface> + '_>;
}

// ...

impl ParentInterface for ConcreteParent {
    fn children(&self) -> Box<dyn Iterator<Item = &dyn ChildInterface> + '_> {
        Box::new(self.my_children.iter().map(|c| c as _))
    }
}
...