Мне нужно создать итератор, которому принадлежит значение (позволяет обернуть объект признака в 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)>>`
Фактическая проблема заключается в том, что у меня есть еще один TStorage
impl (на основе плоских буферов и владеющий vec равным TProduct
), который возвращает Rc
экземпляров (не ссылок), поэтому мне нужно адаптировать черту и эту сигнатуру 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 (детская площадка)