Почему при перемещении значения в замыкание по-прежнему появляется сообщение об ошибке «не может заимствовать неизменяемую локальную переменную как изменяемую»? - PullRequest
0 голосов
/ 28 октября 2018

В приведенном ниже коде я явно заставляю name из функции main перемещаться в замыкание, и все работает просто отлично:

fn main() {
    let name = String::from("Alice");

    let welcome = || {
        let mut name = name;
        name += " and Bob";
        println!("Welcome, {}", name);
    };

    welcome();
}

Я бы подумал, что добавлениеmove к началу закрытия будет выполнять то же самое, что приведет к перемещению значения и созданию FnOnce:

fn main() {
    let name = String::from("Alice");

    let welcome = move || {
        name += " and Bob";
        println!("Welcome, {}", name);
    };

    welcome();
}

Вместо этого, однако, я получаю сообщение об ошибке:

error[E0596]: cannot borrow immutable local variable `welcome` as mutable
 --> main.rs:9:5
  |
4 |     let welcome = move || {
  |         ------- help: make this binding mutable: `mut welcome`
...
9 |     welcome();
  |     ^^^^^^^ cannot borrow mutably

error[E0596]: cannot borrow captured outer variable in an `FnMut` closure as mutable
 --> main.rs:5:9
  |
5 |         name += " and Bob";
  |         ^^^^

Как правильно думать о move на закрытии в этом случае?

1 Ответ

0 голосов
/ 28 октября 2018

Я бы подумал, что добавление move в начало замыкания приведет к тому же результату: ...

Это отчасти делает то же самое.Вы просто забыли объявить name и welcome как изменяемые.Этот код работает нормально:

fn main() {
    let mut name = String::from("Alice");

    let mut welcome = move || {
        name += " and Bob";
        println!("Welcome, {}", name);
    };

    welcome();
}

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

… и приводит к перемещению значения и созданию FnOnce.

Перемещение значения в замыкание не делает его FnOnce.Если замыкание потребляет захваченного значения, оно становится FnOnce, поскольку оно может сделать это только один раз.Таким образом, первая версия замыкания - FnOnce, поскольку она потребляет name.Выше приведено значение FnMut, и его можно вызывать несколько раз.Двойной вызов приводит к выводу

Welcome, Alice and Bob
Welcome, Alice and Bob and Bob

(я использовал несколько небрежных имен признаков функций. Фактически, каждое замыкание реализует FnOnce, так как каждое замыкание может быть вызвано вхотя бы один раз. Некоторые замыкания могут вызываться несколько раз, поэтому они дополнительно FnMut. А некоторые замыкания, которые можно вызывать несколько раз, не изменяют свое захваченное состояние, поэтому они равны Fn в дополнение к двум другим характеристикам.)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...