问题描述
我正在尝试创建一种方法,该方法返回在RefCell
内的HashMap
值上返回的迭代器,但是我遇到了一个错误,其中RefCell::borrow
返回的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
公开了用于映射的普通引用,但是它要求mapper函数返回另一个引用,这在这里是不可能的.我应该重做整个迭代器功能以使用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内部内容有引用的迭代器?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!