функция возвращает замыкание, которое возвращает замыкание, использующее переменную среды - PullRequest
0 голосов
/ 01 октября 2018

functionA возвращает closureA, а closureA возвращает closureB, closureB, которые используют переменную из окружения functionA.

fn main () {
   type Closure1 = Box<Fn() -> ()>;
   type Closure2 = Box<Fn() -> Closure1>;

   fn closure_container() -> Closure2 {
       let mut a: Vec<usize> = Vec::new();
       let closure2: Closure2 = Box::new(move || {
           let closure1 = || {
               println!("{}", a)
           };
           Box::new(closure1)
       });

       closure2
   }
}
error[E0507]: cannot move out of captured outer variable in an `Fn` closure
 --> src/main.rs:9:27
  |
6 |        let mut a: Vec<usize> = Vec::new();
  |            ----- captured outer variable
...
9 |            let closure1 = move || {
  |                           ^^^^^^^ cannot move out of captured outer variable in an `Fn` closure

Компилируется let mut a = 100;, но let mut a: Vec<usize> = Vec::new(); сообщит об ошибке!Я не знаю, как это исправить.

1 Ответ

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

Вы (по праву) использовали move для первого закрытия (строка 7), но вам также необходимо добавить его для второго закрытия (строка 8):

   let closure2: Closure2 = Box::new(move || {
       let closure1 = move || {    // <-- Add "move" on this line
           println!("{}", a)
       };
       Box::new(closure1)
   });

детская площадка

Это работает, если a имеет тип Copy, но вызывает ошибку cannot move out of captured outer variable in an 'Fn' closure, когда a не Copy (например, если a является Vec).Проблема связана с тем, что вы определяете closure2 как Fn, что означает, что вы сообщаете компилятору, что вы можете вызывать его более одного раза.Однако в первый раз, когда вы позвоните closure2, вы переведете a в возвращенное значение closure1, поэтому a не будет доступно для возможного следующего вызова на closure2.

Короче говоря:вам нужно определить closure2 как FnOnce, чтобы сообщить компилятору, что вы не можете вызвать его более одного раза, или вам нужно переместить клон a в closure1, чтобы closure2 сохранил его копию.

Решение 1: FnOnce

type Closure1 = Box<Fn() -> ()>;
type Closure2 = Box<FnOnce() -> Closure1>;

fn closure_container() -> Closure2 {
    let a: Vec<usize> = Vec::new();
    let closure2: Closure2 = Box::new(move || {
        let closure1 = move || {
            println!("{:?}", a)
        };
        Box::new(closure1)
    });

    closure2
}

детская площадка

Обратите внимание, что хотя вы можете создать a Closure2 таким образом, невозможно вызвать в текущем стабильном Rust.Если вы хотите использовать ночной режим, он должен работать, если вы замените FnOnce на FnBox, но я получаю еще одну ошибку с этим ( детская площадка ).Пока вам нужно будет использовать решение 2 и клон a.Если вы хотите избежать затрат на клонирование всего вектора, вы можете обернуть его в Rc и клонировать ( детская площадка ).

Решение 2:Клон

type Closure1 = Box<Fn() -> ()>;
type Closure2 = Box<Fn() -> Closure1>;

fn closure_container() -> Closure2 {
    let a: Vec<usize> = Vec::new();
    let closure2: Closure2 = Box::new(move || {
        let b = a.clone();
        let closure1 = move || {
            println!("{:?}", b)
        };
        Box::new(closure1)
    });

    closure2
}

детская площадка

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