如何将具体类型的迭代器特征对象转换为特征对象的迭代器特征对象?

How can I transform an iterator trait object of concrete types into an iterator trait object of trait objects?

我有一个 trait,它包含一个函数 return 一个迭代器对另一个 trait 的引用,比如:

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

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

在为存储具体值向量的具体类型实现此特征时,如何return编辑正确类型的迭代器?

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() return 是一个错误 Item 类型的迭代器(具体类型而不是特征类型)——这怎么能解决?

默认情况下,特征对象受 '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 _))
    }
}