Replacing element of an array

I got a puzzling problem. I've reduced it to this smallest code, but I still can't find a way to solve it. (In a real world 'foo' is not i32, but a complicated structure, and 'bar' is producing a new structure).

struct Foo{
    foo: i32
}

impl Foo {
    fn bar(self) -> Self{
        self
    }
}

fn main() {
    let mut x: [Option<Foo>;2] = [Some(Foo{foo:1}), Some(Foo{foo:2})];
    x[0] = Some(x[0].unwrap().bar());
}

The compiler error is:

   |
13 |     x[0] = Some(x[0].unwrap().bar());
   |                 ^^^^
   |                 |
   |                 cannot move out of here
   |                 move occurs because `x[_]` has type `std::option::Option<Foo>`, which does not implement the `Copy` trait

Can someone, explain me, how to do it, please? I understand I can't 'move' Option out of array, but how can I replace it?

Assuming your use case is an array of Options as presented, you could do

which is an inlined version of

// replace x[0] with None and zeroth_element becomes the old x[0]
let zeroth_element = x[0].take();
// replace x[0] with the results of bar()
x[0] = zeroth_element.unwrap().bar();

(take documentation)

There may be other approaches if making bar() take by reference makes since, if Foo has a cheap Default, etc.

2 Likes

You can always use mem::replace: something like mem::replace(&mut arr[i], other).

You can always use mem::replace : something like mem::replace(&mut arr[i], other) .

Unless the construction of other requires consuming arr[i] by value.

In that case, you can mem::swap in a placeholder to get the original out to deconstruct, and then mem::replace to put the final built value in.