Есть ли способ сообщить компилятору, что я управляю владением переменной в цикле?

Я пытаюсь передать право собственности на переменную функции в цикле, и у меня есть собственное логическое значение, чтобы гарантировать, что это произойдет только один раз, однако компилятор сообщает мне, что значение было перемещено на предыдущей итерации.

Вот пример:

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);
        }
    }
}

С помощью этого кода компилятор сообщает мне:

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

Есть ли способ сказать компилятору: «Все в порядке, я справлюсь»? Я не хочу использовать ссылки (&).


person Mickael B.    schedule 28.07.2018    source источник


Ответы (1)


Обычный способ сказать компилятору: «Все в порядке, я справлюсь» - использовать unsafe. Вы могли бы использовать unsafe здесь вместе с некоторой глубокой ptr магией, но это было бы чрезвычайно хрупко и трудно доказать, что это правильно.

Однако это безопасно и легко сделать с Option:

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

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

В оригинале между a и hello нет взаимосвязи на уровне типов, поэтому компилятор не может быть уверен, что hello перемещается только один раз. Option кодирует инвариант «здесь может быть что-то здесь или может быть пропало» в типе, поэтому компилятор может знать, что take_ownership вызывается только тогда, когда ему есть что-то передать.

.take() - это метод, заменяющий a на None, возвращая содержимое (если есть). Поскольку этот метод не использует Option, его можно вызывать несколько раз в цикле. Невозможно выйти из заимствованного содержимого при попытке передать право собственности - связанный с этим вопрос.

person trentcl    schedule 28.07.2018