如何返回一个引用了 RefCell 内部内容的迭代器? [英] How do I return an iterator that has a reference to something inside a RefCell?

查看:16
本文介绍了如何返回一个引用了 RefCell 内部内容的迭代器?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试创建一个方法,该方法在 HashMap 的值上返回一个迭代器,该值被装箱在 RefCell 中,但是我遇到了一个错误,其中 <RefCell::borrow 返回的 code>Ref 的存活时间不够长,无法从该方法返回迭代器.这是我的代码:

I'm trying to create a method that returns an iterator over the values of HashMap that is boxed inside a RefCell, but i'm having an error where Ref returned by RefCell::borrow doesn't live long enough for iterator to be returned from the method. Here's my code:

use std::rc::Rc;
use std::cell::RefCell;
use std::collections::HashMap;
use std::collections::hash_map::Values;

struct Foo {
    map: Rc<RefCell<HashMap<i32, i32>>>,
}

impl Foo {
    fn iter(&self) -> Values<i32, i32> {
        self.map.borrow().values()
    }
}

fn main() {
    let foo = Foo {
        map: Rc::new(RefCell::new(HashMap::new()))
    };

    for v in foo.iter() {
        println!("{}", v)
    }
}

编译错误:

rustc 1.15.1 (021bd294c 2017-02-08)
error: borrowed value does not live long enough
  --> <anon>:12:9
   |
12 |         self.map.borrow().values()
   |         ^^^^^^^^^^^^^^^^^ does not live long enough
13 |     }
   |     - temporary value only lives until here
   |

如何我如何在不破坏封装的情况下返回对 RefCell 内某些内容的引用? 建议创建一个封装 Ref 并提供用于访问底层值的接口的保护,但我需要做的是返回一个迭代器对象 (Values<'a, K, V>),它已经封装了对 HashMap 的普通引用.

How do I return a reference to something inside a RefCell without breaking encapsulation? suggests creating a guard that incapsulates Ref and provides an interface for accessing the underlying value, but what I need to do is to return an iterator object (Values<'a, K, V>) that already incapsulates a plain reference to a HashMap.

我的主要问题是我有一个运行时跟踪引用 Ref<T> 而我需要一个普通引用来创建迭代器.Ref::map 公开了一个简单的映射引用,但它需要映射器函数返回另一个引用,这在这里是不可能的.我应该重做整个迭代器功能以使用 Ref 还是有更好的方法?

My main problem is that I have a runtime tracked reference Ref<T> while I need a plain reference to create an iterator. Ref::map exposes a plain reference for mapping, but it requires the mapper function to return another reference which is impossible here. Should I redo the entire iterator functionality to work with Ref or is there a better way?

推荐答案

您不能这样做.

最终的问题是 std::collections::hash_map::Values 持有一个引用,但你没有只是"一个引用.你有智能指针Ref.

The ultimate problem is that std::collections::hash_map::Values holds a reference, but you don't have "just" a reference. You have the smart pointer Ref.

我所知道的最简单的解决方案是反转代码:

The easiest solution I know of is to invert the code:

impl Foo {
    fn with_iter<F, T>(&self, f: F) -> T
    where
        F: FnOnce(Values<i32, i32>) -> T,
    {
        f(self.map.borrow().values())
    }
}

fn main() {
    let foo = Foo {
        map: Rc::new(RefCell::new(HashMap::new())),
    };

    foo.with_iter(|i| {
        for v in i {
            println!("{}", v)
        }
    })
}

在这里,Values 迭代器不再需要比 borrow 的结果更有效,因此没有额外的复杂性.

Here, the Values iterator no longer needs to outlive the result of borrow, so there's no additional complexity.

如果你同意泄露你的实现,你可以返回Ref:

If you are OK with leaking your implementation, you can return the Ref:

impl Foo {
    fn iter(&self) -> Ref<'_, HashMap<i32, i32>> {
        self.map.borrow()
    }
}

for v in foo.iter().values() {
    println!("{}", v)
}

在较新版本的 Rust 中,您可以返回一个实现了 Deref 的未命名类型:

In newer versions of Rust, you can return an unnamed type that implements Deref:

use std::ops::Deref;

impl Foo {
    fn iter(&self) -> impl Deref<Target = HashMap<i32, i32>> + '_ {
        self.map.borrow()
    }
}

另见:

这篇关于如何返回一个引用了 RefCell 内部内容的迭代器?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆