functionA
returns closureA
, and that closureA
returns a closureB
, closureB
which use variable from functionA
's surrounding environment.
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
It compiles let mut a = 100;
, But let mut a: Vec<usize> = Vec::new();
will report a error! I don't know how to fix it.
You have (rightly) used move
for the first closure (line 7), but you need to also add it for the second closure (line 8):
let closure2: Closure2 = Box::new(move || {
let closure1 = move || { // <-- Add "move" on this line
println!("{}", a)
};
Box::new(closure1)
});
This makes it work if a
has a Copy
type, but it causes the error cannot move out of captured outer variable in an 'Fn' closure
when a
is not Copy
(eg if a
is a Vec
). The problem is due to the fact that you are defining closure2
as Fn
, which means that you are telling the compiler that you might want to call it more than once. However the first time you call closure2
will move a
into the returned closure1
, so a
won't be available for a possible next call to closure2
.
Long story short: you need to define closure2
as FnOnce
to tell the compiler that you can't call it more than once, or you need to move a clone of a
into closure1
so that closure2
will keep its copy.
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
}
Note however that although you can create a Closure2
this way, it is impossible to call it in current stable Rust. If you are willing to use nightly, it should work if you replace FnOnce
with FnBox
, but I'm hitting another error with this ( playground ). For the time being, you will need to use solution 2 and clone a
. If you want to avoid the cost of cloning the entire vector, you can wrap it in an Rc
and clone that ( playground ).
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
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.