首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Rust:如何在没有引用的情况下使用生命周期?

Rust:如何在没有引用的情况下使用生命周期?
EN

Stack Overflow用户
提问于 2020-06-21 21:43:48
回答 2查看 138关注 0票数 0

我有这样的代码:

代码语言:javascript
复制
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)));
    }
}

我得到一个错误:

代码语言:javascript
复制
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缓存一样长。但是,由于没有引用,我无法获得任何生命周期。

我该如何解决这个问题?

EN

回答 2

Stack Overflow用户

发布于 2020-06-22 01:37:49

这并没有完全回答这个问题,但可能值得注意的是,生命周期的困难源于使用盒装特征对象来保存返回的迭代器。如果直接返回迭代器,就不会有任何问题:

代码语言:javascript
复制
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,你已经可以使用一个不稳定的特性来做到这一点:

代码语言:javascript
复制
#![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))
    }
}
票数 2
EN

Stack Overflow用户

发布于 2020-06-21 22:30:33

我想表达的是,盒装迭代器的寿命应该和LFU缓存一样长。

into_iter方法使用self,所以这没有意义。只需调用into_iter()即可删除LFU缓存。

如果您想保留它,那么您可以为&LFUCache实现IntoIterator。现在你有了一个引用--也就是生命周期--迭代器可以绑定到这个引用上。请注意,迭代将移动V类型的值,因此您需要将其约束为Copy (或至少为Clone),或者使迭代器项包含对V的引用。以下是使用引用的工作示例:

代码语言:javascript
复制
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)));
    }
}
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/62499405

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档