如何返回一个具有对 RefCell 内部内容引用的迭代器?

5

我正在尝试创建一个方法,该方法返回一个迭代器,用于访问包含在RefCell中的 HashMap 的值,但是我遇到了一个错误,即由RefCell::borrow返回的Ref的生命周期不足以支持从该方法返回迭代器。这是我的代码:

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并提供访问底层值的接口,但我需要做的是返回一个已经封装了对HashMap的普通引用的迭代器对象(Values<'a,K,V>)。 我的主要问题是我有一个运行时跟踪的引用Ref,而我需要一个普通引用来创建迭代器。 Ref::map公开了一个用于映射的普通引用,但它要求映射函数返回另一个引用,在这里是不可能的。 我应该重新设计整个迭代器功能以使用Ref,还是有更好的方法?


相关:从RefCell<T>中返回借用的T - Shepmaster
1个回答

5

你不能这样做。

根本问题在于 std::collections::hash_map::Values 持有一个引用,但你不只是持有一个引用,而是智能指针 Ref

我知道的最简单的解决方案是颠倒代码执行:

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的结果更长寿,因此没有额外的复杂性。
如果您可以接受泄露您的实现,可以返回Ref
impl Foo {
    fn iter(&self) -> Ref<'_, HashMap<i32, i32>> {
        self.map.borrow()
    }
}

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

在较新的Rust版本中,你可以返回一个实现了Deref trait的匿名类型:

use std::ops::Deref;

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

参见:


你可能可以使用unsafe代码来完成这个任务,但是我目前的大脑无法指引我。 - Shepmaster
也许可以使用RefCell::as_ptr - trent
等等,你还需要调整'RefCell'的内容,以确保在'Values'存在的同时没有其他人将其作为可变对象进行借用。这有点棘手。 - trent

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接