我有这样的代码:
use std::hash::Hash;
use std::rc::Rc;
struct Counter<V> {
value: V,
}
struct LFUCache<K, V> {
values: Vec<(Rc<K>, Counter<V>)>,
}
impl<K: Hash + Eq, V> IntoIterator for LFUCache<K, V> {
type Item = (Rc<K>, V);
type IntoIter = Box<dyn Iterator<Item=(Rc<K>, V)>>;
fn into_iter(self) -> Self::IntoIter {
return Box::new(self
.values
.into_iter()
.map(|(key, value_counter)| (key, value_counter.value)));
}
}我得到一个错误:
error[E0310]: the parameter type `K` may not live long enough
--> src/lib.rs:167:16
|
162 | impl<K: Hash + Eq, V> IntoIterator for LFUCache<K, V> {
| -- help: consider adding an explicit lifetime bound `K: 'static`...
...
167 | return Box::new(self
| ________________^
168 | | .values
169 | | .into_iter()
170 | | .map(|(key, value_counter)| (key, value_counter.value)));
| |____________________________________________________________________^
|
note: ...so that the type `std::iter::Map<std::collections::hash_map::IntoIter<std::rc::Rc<K>, ValueCounter<V>>, [closure@src/lib.rs:170:18: 170:67]>` will meet its required lifetime bounds
--> src/lib.rs:167:16
|
167 | return Box::new(self
| ________________^
168 | | .values
169 | | .into_iter()
170 | | .map(|(key, value_counter)| (key, value_counter.value)));我想表达的意图是,盒装迭代器应该和LFU缓存一样长。但是,由于没有引用,我无法获得任何生命周期。
我该如何解决这个问题?
发布于 2020-06-22 01:37:49
这并没有完全回答这个问题,但可能值得注意的是,生命周期的困难源于使用盒装特征对象来保存返回的迭代器。如果直接返回迭代器,就不会有任何问题:
use std::hash::Hash;
use std::rc::Rc;
use std::{iter, vec};
struct Counter<V> {
value: V,
}
struct LFUCache<K, V> {
values: Vec<(Rc<K>, Counter<V>)>,
}
impl<K: Hash + Eq, V> IntoIterator for LFUCache<K, V> {
type Item = (Rc<K>, V);
type IntoIter =
iter::Map<vec::IntoIter<(Rc<K>, Counter<V>)>, fn((Rc<K>, Counter<V>)) -> (Rc<K>, V)>;
fn into_iter(self) -> Self::IntoIter {
self.values
.into_iter()
.map(|(key, value_counter)| (key, value_counter.value))
}
}通过避免Box分配和vtable查找,这也可能具有更好的性能。这里的缺点是迭代器有一个您必须编写的相当复杂的类型。最后,Rust的"impl特征“功能可以扩展以涵盖这种情况,这样您就不必显式地编写类型。事实上,使用nightly Rust,你已经可以使用一个不稳定的特性来做到这一点:
#![feature(type_alias_impl_trait)]
impl<K: Hash + Eq, V> IntoIterator for LFUCache<K, V> {
type Item = (Rc<K>, V);
type IntoIter = impl Iterator<Item = (Rc<K>, V)>;
fn into_iter(self) -> Self::IntoIter {
self.values
.into_iter()
.map(|(key, value_counter)| (key, value_counter.value))
}
}发布于 2020-06-21 22:30:33
我想表达的是,盒装迭代器的寿命应该和LFU缓存一样长。
into_iter方法使用self,所以这没有意义。只需调用into_iter()即可删除LFU缓存。
如果您想保留它,那么您可以为&LFUCache实现IntoIterator。现在你有了一个引用--也就是生命周期--迭代器可以绑定到这个引用上。请注意,迭代将移动V类型的值,因此您需要将其约束为Copy (或至少为Clone),或者使迭代器项包含对V的引用。以下是使用引用的工作示例:
impl<'a, K: Hash + Eq, V> IntoIterator for &'a LFUCache<K, V> {
type Item = (Rc<K>, &'a V);
type IntoIter = Box<dyn Iterator<Item=(Rc<K>, &'a V)> + 'a>;
fn into_iter(self) -> Self::IntoIter {
return Box::new(self
.values
.iter()
.map(|(key, value_counter)| (key.clone(), &value_counter.value)));
}
}https://stackoverflow.com/questions/62499405
复制相似问题