首页 文章

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

提问于
浏览
2

我试图创建一个返回了这是一个 RefCell 内盒装的 HashMap 值是迭代器的方法,但我在这里 Ref 通过 RefCell::borrow 没有按't live long enough for iterator to be returned from the method. Here'是我的代码返回了一个错误:

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
   |

How do I return a reference to something inside a RefCell without breaking encapsulation?建议创建incapsulates Ref ,并提供一个接口,用于访问基础值保护,但我需要做的就是返回一个迭代对象( Values<'a, K, V> )已经incapsulates普通参照 HashMap .

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

1 回答

  • 3

    你不能做这个 .

    最终的问题是 std::collections::hash_map::Values 拥有一个引用,但你没有"just"引用 . 你有智能指针 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 的未命名类型:

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

    也可以看看:

相关问题