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

时间:2019-06-07 14:16:58

标签: reference rust iterator traits

我有一个特征,该特征包含一个函数,该函数返回对另一个特征的引用的迭代器,例如:

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 个答案:

答案 0 :(得分:2)

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