1

I'm trying to give ownership of a variable to a function in a loop and I have my own boolean to ensure it happens only one time, however the compiler tells me the value was moved in the previous iteration.

Here is an example:

fn take_ownership(a: String) {
    println!("{}", a);
}

fn main() {
    let mut a = true;
    let hello = "Hello".to_string();

    for _ in 0..5 {
        if a {
            a = false;
            take_ownership(hello);
        }
    }
}

With this code, the compiler tells me:

error[E0382]: use of moved value: `hello`
  --> src/main.rs:12:28
   |
12 |             take_ownership(hello);
   |                            ^^^^^ value moved here in previous iteration of loop

Is there a way to tell the compiler "it's ok, I will handle it"? I don't want to use references (&).

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
Mickael B.
  • 4,755
  • 4
  • 24
  • 48

1 Answers1

6

The usual way of telling the compiler "It's OK, I will handle it" is to use unsafe. You could use unsafe here along with some deep ptr magic, but that would be extremely brittle and difficult to prove correct.

However, this is a safe and easy thing to do with an Option:

let mut a = Some("Hello".to_string());

for _ in 0..5 {
    if let Some(hello) = a.take() {
        take_ownership(hello);
    }
}

In the original, there's no type-level relationship between a and hello, so the compiler can't be sure that hello is only moved once. Option encodes the invariant "there might be a thing here, or it might be gone" into the type, so the compiler can know that take_ownership is only called when there is something to pass to it.

.take() is a method that replaces a with None, returning the contents (if any). Because this method does not consume the Option, it's fine to call it multiple times in a loop. Cannot move out of borrowed content when trying to transfer ownership is a related question.

trent
  • 25,033
  • 7
  • 51
  • 90