当前位置: 首页 > 知识库问答 >
问题:

在Rust中拥有迭代器?

左丘兴生
2023-03-14

我需要创建一个拥有该值的迭代器(允许将 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)>>`

实际问题是我有另一个< code>TStorage impl(基于flatbuffers并拥有< code>TProduct的vec)返回< code>Rc实例(不是引用),因此我也需要修改trait和这个impl签名。

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

我尝试过修改flatbuffers impl来返回引用的迭代器,但是它不像预期的那样工作,因为它不能保存临时创建的对象:

&Rc::new(each_product)

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

另外,我尝试过克隆包装器(它克隆了Rc并因此返回一个实例,而不是一个引用),但由于生命周期的原因,它不起作用(例如:

// 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。与奶牛有相同的终身问题(游乐场)

共有1个答案

邴墨竹
2023-03-14

正如Stargateur指出的那样,< code>Iterator已经有了一个内置的克隆适配器:< code>Iterator::cloned。所以你可以用它来得到一个< code >迭代器

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=_>>
            })
    }
}

除了< code>iter()与< code>into_iter()无关紧要,您的输入是一个< code >

 类似资料:
  • null 一些示例输出数据: *编辑:工作的scala代码行:

  • 问题内容: Python迭代器没有方法吗? 问题答案: 不,没有这样的方法。迭代结束由异常指示。请参阅文档。

  • 我天真地试图这样做: 要创建迭代器,我可以使用闭包轻松地发送到任务。 但是,它会产生可怕的寿命不匹配错误: 我不明白这个错误。 闭包应采用生命周期为“a”的参数,即结构的生命周期。 国家为结构所有,因此其生命周期为“a”。 使用下一步。召唤(( 所以这里的不匹配是下一个()中的自我终生和“呼叫中的a”之间的不匹配...但我不明白为什么它不是“a”。 修复上述代码的正确方法是什么? 有没有更好的方法

  • 问题内容: 您能想到一种很好的方法(也许使用itertools)将迭代器拆分为给定大小的块吗? 因此,with成为迭代器 我可以想到一个小程序来做到这一点,但是使用itertools并不是一个好方法。 问题答案: 在 从配方文件的食谱来靠近你想要什么: 但是,它将使用填充值填充最后一个块。 较不通用的解决方案仅适用于序列,但可以根据需要处理最后一个块 最后,一种可在一般迭代器上运行且其行为符合预期

  • 我想写一个模拟 DNF 装备增幅的程序,通过多次样本执行得到平均每件增幅 10 装备需要增幅多少次。装备 +4 之前不会失败,+4 之后会失败且失败后还会掉级,具体如下图所示: 公会秘药和普雷宠物会额外增加每次增幅的成功率 1% 和 4%,所以一共分了三种情况。 我最开始用 js 写了一版: 后来想到我刚学了 rust,不如练练手,而且 rust 很快,于是又写了一版: 然而实际上 rust 代码