Mar*_*rik 5 iterator reference rust interior-mutability
我试图创建一个方法,它返回了值的迭代器HashMap是内部的盒装RefCell,但我在那里的错误Ref被退回RefCell::borrow 不足够长寿的迭代器从该方法返回。这是我的代码:
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)
}
}
Run Code Online (Sandbox Code Playgroud)
编译错误:
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)
}
}
Run Code Online (Sandbox Code Playgroud)
如何在不破坏封装的情况下返回对 RefCell 内某些内容的引用?建议创建一个封装Ref并提供访问底层值的接口的守卫,但我需要做的是返回一个迭代器对象 ( Values<'a, K, V>),它已经封装了对HashMap.
我的主要问题是我有一个运行时跟踪引用,Ref<T>而我需要一个普通引用来创建迭代器。Ref::map公开一个用于映射的普通引用,但它需要映射器函数返回另一个引用,这在这里是不可能的。我应该重做整个迭代器功能Ref还是有更好的方法?
你不可以做这个。
最终的问题是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)
}
})
}
Run Code Online (Sandbox Code Playgroud)
在这里,Values迭代器不再需要超过 的结果borrow,因此没有额外的复杂性。
如果您同意泄露您的实现,您可以返回Ref:
impl Foo {
fn iter(&self) -> Ref<'_, HashMap<i32, i32>> {
self.map.borrow()
}
}
Run Code Online (Sandbox Code Playgroud)
for v in foo.iter().values() {
println!("{}", v)
}
Run Code Online (Sandbox Code Playgroud)
在较新版本的 Rust 中,您可以返回一个未命名的类型,它实现了Deref:
use std::ops::Deref;
impl Foo {
fn iter(&self) -> impl Deref<Target = HashMap<i32, i32>> + '_ {
self.map.borrow()
}
}
Run Code Online (Sandbox Code Playgroud)
也可以看看: