Is there a way to add elements to a container whil

2019-08-02 07:56发布

问题:

I'm building a GUI and I want to store all used textures in one place, but I have to add new textures while older textures are already immutably borrowed.

let (cat, mouse, dog) = (42, 360, 420); // example values

let mut container = vec![cat, mouse]; // new container

let foo = &container[0]; // now container is immutably borrowed

container.push(dog); // error: mutable borrow

Is there any kind of existing structure that allows something like this, or can I implement something like this using raw pointers?

回答1:

The absolute easiest thing is to introduce shared ownership:

use std::rc::Rc;

fn main() {
    let (cat, mouse, dog) = (42, 360, 420);
    let mut container = vec![Rc::new(cat), Rc::new(mouse)];
    let foo = container[0].clone();
    container.push(Rc::new(dog));
}

Now container and foo jointly own cat.

Is there any kind of existing structure that allows something like this,

Yes, but there are always tradeoffs. Above, we used Rc to share ownership, which involves a reference counter.

Another potential solution is to use an arena:

extern crate typed_arena;

use typed_arena::Arena;

fn main() {
    let container = Arena::new();
    let cat = container.alloc(42);
    let mouse = container.alloc(360);
    let dog = container.alloc(420);
}

This isn't indexable, you cannot take ownership of the value again, and you cannot remove a value.

Being able to remove things from the collection always makes invalidating references dangerous.

can I implement something like this using raw pointers

Almost certainly. Will you get it right is always the tricky point.

but I have to add new textures while older textures are already immutably borrowed

Many times, you don't have to do any such thing. For example, you can split up your logic into phases. You have two containers; one that people take references into, and another to collect new values. At the end of the phase, you combine the two collections into one. You have to ensure that no references are used after the end of the phase, of course.