Rust中拥有迭代器



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

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)>>`

实际问题是,我有另一个返回Rc实例(而不是引用(的TStorageimpl(基于平面缓冲区并拥有TProduct的向量(,因此我也需要调整trait和这个impl签名。

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

我曾尝试将flatbuffers impl调整为返回引用的迭代器,但由于它不能容纳临时创建的对象,所以预计它不会起作用:

&Rc::new(each_product)

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

PS。我尝试过克隆包装器(它克隆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.与Cow(游乐场(有相同的终身问题

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

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

最新更新