简体   繁体   中英

How to iterate over an Rc<RefCell<T>> that returns raw mutable references

I have a Vec<Rc<RefCell<MyStruct>>> member on a struct and I have an external library function that expects to be handed an Iterator with an Item that is a &'a mut dyn LibTrait which I have as a member inside MyStruct . I can't figure out how to get a raw &mut from out of the Rc<RefCell<MyStruct>> in my iterator even though I know the Vec member that holds it will stick around for longer than either the iterator or the function that gets passed the iterator.

The library looks like this:

struct Lib {}

trait LibTrait {
    fn run(&mut self);
}

impl Lib {
    pub fn lib_func<'a, Iter>(&mut self, trait_iter: Iter)
    where
        Iter: Iterator<Item = &'a mut dyn LibTrait>,
    {
        ...
    }
}

Here's my latest attempt where I tried to create a temp Vec to hold RefMut's to all the MyStructs so that those refs are owned for the whole time that the &mut would be inside the iterator and lib function. (This code complains about "cannot infer an appropriate lifetime for lifetime parameter in function call due to conflicting requirements".)

struct TraitImpl {
    dummy: f32,
}
impl LibTrait for TraitImpl {
    fn run(&mut self) {
        self.dummy += 1.0;
    }
}

struct MyStruct {
    my_impl: TraitImpl,
    num: f32,
}

type MutStructSlice<'a> = &'a mut [&'a mut MyStruct];
struct TraitIterator<'a> {
    my_structs: MutStructSlice<'a>,
    index: usize,
}

impl<'a> TraitIterator<'a> {
    fn new(my_structs: MutStructSlice<'a>) -> Self {
        Self {
            my_structs,
            index: 0,
        }
    }
}

impl<'a> Iterator for TraitIterator<'a> {
    type Item = &'a mut dyn LibTrait;

    fn next(&mut self) -> Option<&'a mut dyn LibTrait> {
        if self.index >= self.my_structs.len() {
            return None;
        }

        Some(&mut self.my_structs[self.index].my_impl)
    }
}

struct Data {
    data: Vec<Rc<RefCell<MyStruct>>>,
    lib: Lib,
}

impl Data {
    fn do_stuff(&mut self) {
        let mut struct_refs: Vec<RefMut<MyStruct>> = self
            .data
            .iter_mut()
            .map(|s_rc| s_rc.borrow_mut())
            .collect();
        let mut structs_raw_refs: Vec<&mut MyStruct> =
            struct_refs.iter_mut().map(|s_ref| &mut **s_ref).collect();
        self.lib.lib_func(TraitIterator::new(&mut structs_raw_refs));
    }
}

Here's the playground

Is there some way around this given that I can't change the library and I need to have Rc<RefCell<>>'s to the data?

I think you're overcomplicating this. You don't need a custom iterator, you can do this with .map() :

fn do_stuff(&mut self) {
    let mut struct_refs: Vec<RefMut<MyStruct>> = self.data
        .iter_mut()
        .map(|s_rc| s_rc.borrow_mut())
        .collect();

    self.lib.lib_func(struct_refs.iter_mut().map(|s_ref| &mut s_ref.my_impl as &mut dyn LibTrait));
}

You get the error you did because implementing Iterator for &mut T is inherently unsafe. See How to implement Iterator yielding mutable references .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM