How do I return an iterator that has a reference to something inside a RefCell?

后端 未结 1 1620
梦毁少年i
梦毁少年i 2020-12-11 21:38

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 <

相关标签:
1条回答
  • You cannot do this.

    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)
            }
        })
    }
    

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

    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)
    }
    

    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()
        }
    }
    

    See also:

    • How do I return a reference to something inside a RefCell without breaking encapsulation?
    0 讨论(0)
提交回复
热议问题