Get Option from Vec by index without moving

Hello! I've created a play for my program

Briefly: I have a Vec<Option<Box<dyn SomeTrait>>> and want to get an element by index to send it to a function. And I don't wanna to take this element - the source Vec should be untouched. How can I do this?

1 Like

Without using shared ownership pointer types like Rc or Arc, there can only be one owner of a resource, which is the vector in your example. If you can't hand out (mutable) references to its elements, you can clone an element—thus avoiding moving it from the vector—and move the clone to your some function.

If you do not want to take the element you have two options. Either you change the function signature to accept a reference &dyn SomeTrait or you clone the element. For cloning you can either switch from Box to Arc or cou can add a

fn clone_boxed(&self) -> Box<dyn SomeTrait>

function to SomeTrait.

2 Likes

I'd happy to clone it but I don't know how to do it. Rust Playground

Box is a type that can only exist in one place (like most Rust types, it's exclusively owned). That's the requirement of the type, just like u32 can't be -1. If you don't want the exclusive ownership, you need a different type like Arc.

If a function requires Box by move, then the value is not allowed to stay anywhere else (unless you make a clone, but dyn Trait isn't cloneable).

Change the function to take a reference instead. &dyn Trait is a non-owning alternative to Box<dyn Trait> arguments, and it doesn't require always boxing the type, so it can be cheaper if you don't already have concrete type in a Box.

It works!

....
impl SomeTrait for SomeImpl {
    fn id(&self) -> String {
        self.id.to_string()
    }
    fn clone_boxed(&self) -> Box<dyn SomeTrait> {
        Box::new(self.clone())
    }
}

......

    fn work(&mut self) {
        for i in 0..5 {
            some(Some(self.somes[i].as_ref().unwrap().clone_boxed()));
        }
        for i in 0..5 {
            some(Some(self.somes[i].as_ref().unwrap().clone_boxed()));
        }
    }

Thank you!

1 Like