Невозможно выйти из захваченной внешней переменной в замыкании Fn - PullRequest
0 голосов
/ 24 апреля 2018
fn make_adder(x: String) -> Box<Fn() -> String> {
    Box::new(|| x)
}

fn main() {
    make_adder(String::from("a"));
}

Это приводит к этой ошибке:

error[E0507]: cannot move out of captured outer variable in an `Fn` closure
 --> src/main.rs:2:17
  |
1 | fn make_adder(x: String) -> Box<Fn() -> String> {
  |               - captured outer variable
2 |     Box::new(|| x)
  |                 ^ cannot move out of captured outer variable in an `Fn` closure

Как я могу исправить это?

1 Ответ

0 голосов
/ 24 апреля 2018

Закрытие, которое реализует Fn , может быть вызвано несколько раз (параметр получателя &self, неизменная ссылка на замыкание):

fn call_multiple_times<F: Fn(u8) -> i32>(f: F) {
    // Works! We can call the closure mutliple times
    let a = f(1);
    let b = f(27);
    let c = f(31);
}

Это означает, что с вашим закрытием Fn() -> String вы можете сделать следующее:

let s1 = adder();
let s2 = adder();

Теперь у вас будет два String с, хотя вы только начали с одного!Магия? Конечно, вы можете получить еще одну строку, клонируя исходную строку, но мы здесь этого не делаем.Так что это явно не может работать.


Это можно исправить двумя способами.Либо вам не нужно, чтобы ваше закрытие вызывалось несколько раз.В этом случае вы можете просто изменить Fn на FnOnce (менее требовательная черта).Закрытие FnOnce можно назвать ... ну ... один раз.Это работает:

fn make_adder(x: String) -> Box<FnOnce() -> String> {
    Box::new(|| x)
}

С другой стороны, возможно, вы хотите, чтобы замыкание вызывалось несколько раз, и всегда хотите вернуть новый клон строки.Вы можете сделать это следующим образом:

fn make_adder(x: String) -> Box<Fn() -> String> {
    Box::new(move || x.clone())
}

Здесь мы добавили вызов .clone() (поскольку в Rust глубокие клоны никогда не подразумеваются!) И добавили ключевое слово move.Последнее необходимо для явного перемещения строки x в замыкание, а не просто для ее заимствования.

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