问题
I have the following minimal example of my code:
fn main()
{
let names : Vec<Vec<String>> = vec![
vec!["Foo1".to_string(), "Foo2".to_string()],
vec!["Bar1".to_string(), "Bar2".to_string()]
];
let ids : Vec<i64> = vec![10, 20];
names.iter().enumerate().flat_map(|(i,v)| {
let id : i64 = ids[i];
v.iter().map(|n|
(n.clone(), id)
)
});
}
Now, when I compile that with rustc
I get the following error message:
error[E0597]: `id` does not live long enough
--> main.rs:12:16
|
11 | v.iter().map(|n|
| --- capture occurs here
12 | (n.clone(), id)
| ^^ borrowed value does not live long enough
13 | )
14 | });
| -- borrowed value needs to live until here
| |
| borrowed value only lives until here
But in my understanding, id
is of type i64
and should therefore be able to be copied into the capture, with would be exactly what I need?
I've also tried to inline the id
variable but to no avail:
error[E0597]: `i` does not live long enough
--> main.rs:11:21
|
10 | v.iter().map(|n|
| --- capture occurs here
11 | (n.clone(), ids[i])
| ^ borrowed value does not live long enough
12 | )
13 | });
| -- borrowed value needs to live until here
| |
| borrowed value only lives until here
So how can I copy my integer into the closure instead of borrowing it?
I tried using move
, but rustc
doesn't like that either:
error[E0507]: cannot move out of captured outer variable in an `FnMut` closure
--> main.rs:10:17
|
7 | let ids : Vec<i64> = vec![10, 20];
| --- captured outer variable
...
10 | v.iter().map(move |n|
| ^^^^^^^^ cannot move out of captured outer variable in an `FnMut` closure
So I'd somehow need to get rustc
to only move/copy some but not the other variable?
回答1:
When you create a closure in Rust, it captures the variables either by value or by reference. A mix of both is impossible. By default, it captures by reference, but with the move
keyword, it captures by value (i.e. it moves the captured variables inside the closure).
So, in your first code, you need to move id
inside the closure:
fn main() {
let names: Vec<Vec<String>> = vec![
vec!["Foo1".to_string(), "Foo2".to_string()],
vec!["Bar1".to_string(), "Bar2".to_string()],
];
let ids: Vec<i64> = vec![10, 20];
names.iter().enumerate().flat_map(|(i, v)| {
let id: i64 = ids[i];
v.iter().map(move |n| (n.clone(), id))
});
}
Then you ask if you can "inline" ids
:
fn main() {
let names: Vec<Vec<String>> = vec![
vec!["Foo1".to_string(), "Foo2".to_string()],
vec!["Bar1".to_string(), "Bar2".to_string()],
];
let ids: Vec<i64> = vec![10, 20];
names.iter().enumerate().flat_map(|(i, v)| {
v.iter().map(|n| (n.clone(), ids[i]))
});
}
You cannot put ids
at all in your inner closure, because you are already inside a FnMut
closure (that requires exclusive access). Thus, you cannot borrow or move ids
because it is already borrowed by the FnMut
closure. Minimal reproduction:
fn main() {
let mut i = 0;
let mut closure = || {
i = 2;
|| {
println!("i = {}", i);
}
};
closure()();
}
回答2:
You can move the variable into closure with move
keyword. Here you need to change the closure like:
v.iter().map(move |n| // move is the keyword for moving variables into closure scope.
(n.clone(), id)
)
Playground
来源:https://stackoverflow.com/questions/54287719/how-to-copy-instead-of-borrow-an-i64-into-a-closure-in-rust