微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

在 Rust 中拥有迭代器?

如何解决在 Rust 中拥有迭代器?

我需要创建一个拥有该值的迭代器(允许将 trait 对象包装到 Rc)并将其作为 next() 值(playground)返回:

use std::rc::Rc;
use std::collections::HashMap;

trait TProduct {
    fn get_title(&self) -> String;
}

struct Product {
    title: String
}

impl<'a> TProduct for Product {
    fn get_title(&self) -> String { self.title }
}

trait TStorage<'a> {
    fn get_products(&self,key: &str) -> Option<Box<dyn Iterator<Item=Rc<dyn TProduct + 'a>> + '_>>;
}

struct Storage<'a> {
    products: HashMap<String,Vec<Rc<dyn TProduct + 'a>>>
}

impl<'a> TStorage<'a> for Storage<'a> {
    fn get_products(&self,key: &str) -> Option<Box<dyn Iterator<Item=Rc<dyn TProduct + 'a>> + '_>> {
        self.products.get(key)
            .map(|it| {
                let iter = it.into_iter(); // iter of &Rc,but we need owning iter (of Rc)
                let Boxed_iter: Box<dyn Iterator<Item=Rc<dyn TProduct + 'a>>> = Box::new(iter); // problem here
                Boxed_iter
            })
    }
}

fn main() {
    println!("Hello,world!");
}

我得到以下信息:

430 |                 let Boxed_iter: Box<dyn Iterator<Item=Rc<dyn TProduct + 'a>>> = Box::new(iter);
    |                                                                                 ^^^^^^^^^^^^^^ expected struct `Rc`,found reference
    |
    = note: expected struct `Rc<(dyn TProduct + 'a)>`
            found reference `&Rc<dyn TProduct>`
    = note: required for the cast to the object type `dyn Iterator<Item = Rc<(dyn TProduct + 'a)>>`

实际问题是我有一个 TStorage impl(基于 flatbuffers 并拥有 TProduct 的 vec)返回 Rc 实例(不是引用),因此我需要适应trait 和 this impl 签名也是如此。

我知道当前的迭代器借用 vec 对象(并且不会移动它们)。 是否可以返回拥有迭代器?是否可以使用包装器/适配器(接受对 Rc 的引用并克隆它)来完成?

我试图调整 flatbuffers impl 以返回引用的迭代器,但它预计不起作用,因为它不能保存临时创建的对象:

&Rc::new(each_product)

我一直在考虑使用 Cow,但我得到了一些其他与生命周期相关的错误输出

附注。我试过克隆包装器(克隆 Rc 并因此返回一个实例,而不是引用),但由于生命周期(playground),它不起作用:

// converts `&Rc` into `Rc`
struct cloningWrapper<'a> {
    iter: std::slice::Iter<'a,Rc<dyn TProduct + 'a>>
}

impl<'a> Iterator for cloningWrapper<'a> {
    type Item = Rc<dyn TProduct + 'a>;
    fn next(&mut self) -> Option<Self::Item> {
        self.iter.next().map(|it| {
            it.clone()
        })
    }
}

impl<'a> TStorage<'a> for Storage<'a> {
    fn get_products(&self,key: &str) -> Option<Box<dyn Iterator<Item=Rc<dyn TProduct + 'a>> + '_>> {
        self.products.get(key) // problem here
            .map(|it| {
                let iter = it.into_iter();
                let wrapped_iter = cloningWrapper { iter };
                let Boxed_iter: Box<dyn Iterator<Item=Rc<dyn TProduct + 'a>>> = Box::new(wrapped_iter);
                Boxed_iter
            })
    }
}

由于以下原因:

error[E0495]: cannot infer an appropriate lifetime for autoref due to conflicting requirements
  --> src/main.rs:40:23
   |
40 |         self.products.get(key)
   |                       ^^^
   |
note: first,the lifetime cannot outlive the anonymous lifetime #1 defined on the method body at 39:5...
  --> src/main.rs:39:5
   |
39 |     fn get_products(&self,key: &str) -> Option<Box<dyn Iterator<Item=Rc<dyn TProduct + 'a>> + '_>> {
   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: ...so that reference does not outlive borrowed content

PPS2。与 Cow (playground) 有相同的终生问题

解决方法

Stargateur 指出,Iterator 已经有一个内置的克隆适配器:Iterator::cloned。因此,您可以使用它来获取 Iterator<Item=Rc<_>>,然后将其转换为相关的 trait 对象:

impl<'a> TStorage<'a> for Storage<'a> {
    fn get_products(&self,key: &str) -> Option<Box<dyn Iterator<Item=Rc<dyn TProduct + 'a>> + '_>> {
        self.products.get(key)
            .map(|it| {
                Box::new(it.into_iter().cloned()) as Box<dyn Iterator<Item=_>>
            })
    }
}

除了 iter()into_iter() 无关紧要,您的输入是 &Vec,因此无论哪种方式您都会得到 std::slice::Iter

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。