在 Rust 中拥有迭代器?
Owning iterator in Rust?
我需要创建一个拥有该值的迭代器(允许将 trait 对象包装到 Rc
)并且 return 它作为 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)returns Rc
个实例(不是引用), 因此我也需要调整 trait 和 this impl 签名。
我知道当前迭代器借用 vec 对象(并且不会移动 它们)。
是否可以 return 拥有迭代器?可以用 wrapper/adapter 来完成吗(接受对 Rc 的引用并克隆它)?
我已经尝试使 flatbuffers impl 适应 return 引用迭代器,但它预计不会工作,因为它不能容纳临时创建的对象:
&Rc::new(each_product)
我一直在考虑使用 Cow
,但我得到了一些其他与生命周期相关的错误输出。
PS。我试过克隆包装器(克隆 Rc,因此 returns 是一个实例,而不是引用),但由于生命周期 (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<_>>
,然后把它转换成相关的特征对象:
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
。
我需要创建一个拥有该值的迭代器(允许将 trait 对象包装到 Rc
)并且 return 它作为 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)returns Rc
个实例(不是引用), 因此我也需要调整 trait 和 this impl 签名。
我知道当前迭代器借用 vec 对象(并且不会移动 它们)。 是否可以 return 拥有迭代器?可以用 wrapper/adapter 来完成吗(接受对 Rc 的引用并克隆它)?
我已经尝试使 flatbuffers impl 适应 return 引用迭代器,但它预计不会工作,因为它不能容纳临时创建的对象:
&Rc::new(each_product)
我一直在考虑使用 Cow
,但我得到了一些其他与生命周期相关的错误输出。
PS。我试过克隆包装器(克隆 Rc,因此 returns 是一个实例,而不是引用),但由于生命周期 (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<_>>
,然后把它转换成相关的特征对象:
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
。