I'd like to move some Boxed values from one Vec to another, but I can't figure out if this is possible or whether I'm thinking about it wrong.
So far, my smallest example of the problem is:
#[derive(Debug)] pub struct B { value: usize } fn main() { let v1: Vec<_> = (1..3).map(|i| Box::new(B{ value: i})).collect(); let v2: Vec<Box<B>> = v1.iter().map(|b| *b).collect(); println!("{v2:?}"); } Which gives the error:
error[E0507]: cannot move out of `*b` which is behind a shared reference --> src/main.rs:8:45 | 8 | let v2: Vec<Box<B>> = v1.iter().map(|b| *b).collect(); | ^^ move occurs because `*b` has type `Box<B>`, which does not implement the `Copy` trait I've tried various (but possibly incorrect) methods of trying to move the contents of the Box with std::mem::swap and friends, but haven't managed to get that right.
For clarity, I want to avoid copying the B's - in reality they are large. I haven't experimented with an Rc, and ideally I'd avoid that. v1 is effectively consumed when it is mapped into v2.
As shown above, the example is pretty uninteresting, in the "real" case, v1 is a Vec of 2-tuples, and I'd like to map it to a Vec of 3-tuples with an extra element derived from the first two.
I'm aware I don't need all the type annotation, but that helps check I'm getting what I want. For a while I thought I had succeeded, but was actually getting a Vec<&Box<B>> (or similar, don't take my exact word for it).
Does anyone have any insight as to how to do this, or how I can approach the problem differently? Thanks!
v1is effectively consumed when it is mapped tov2", but when you writev1.iter(), you are borrowing v1, so you can't move anything, because you don't have access to the values, only references. So your only choice is to clone the box (and its contents). Rust doesn't do "effectively moved", something is either actually moved or it's not. If you want to consumev1in the creation ofv2you can do that, by callingv1.into_iter(). This will create an "owning" iterator from the vector itself, and thus will move the contents.v1is to be consumed, then just dolet v2 = v1.into_iter().collect();plus, presumably, whatever transformations you want on the items.into_iteris the answer I was looking for. Thank you!