Как скопировать вместо заимствования i64 в замыкание в Rust?
У меня есть следующий минимальный пример моего кода:
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)
)
});
}
Теперь, когда я собираю это с rustc
Я получаю следующее сообщение об ошибке:
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
Но в моем понимании id
имеет тип i64
и поэтому должен быть в состоянии быть скопирован в захват, будет ли именно то, что мне нужно?
Я также пытался включить id
переменная, но безрезультатно:
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
Так как же я могу скопировать свое целое число в замыкание вместо того, чтобы заимствовать его?
Я пытался с помощью move
, но rustc
это тоже не нравится
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
Так что мне как-то нужно получить rustc
перемещать / копировать только некоторые, но не другую переменную?
2 ответа
Когда вы создаете замыкание в Rust, оно захватывает переменные либо по значению, либо по ссылке. Сочетание обоих невозможно. По умолчанию он захватывает по ссылке, но с move
ключевое слово, оно захватывает по значению (то есть перемещает захваченные переменные внутри замыкания).
Итак, в вашем первом коде, вам нужно переместить id
внутри закрытия:
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))
});
}
Затем вы спрашиваете, можете ли вы "встроить" 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]))
});
}
Вы не можете поставить ids
вообще в вашей внутренней замкнутости, потому что вы уже внутри FnMut
закрытие (это требует эксклюзивного доступа). Таким образом, вы не можете одолжить или переместить ids
потому что он уже заимствован FnMut
закрытие. Минимальное воспроизведение:
fn main() {
let mut i = 0;
let mut closure = || {
i = 2;
|| {
println!("i = {}", i);
}
};
closure()();
}
Вы можете переместить переменную в закрытие с помощью move
ключевое слово. Здесь вам нужно изменить замыкание как:
v.iter().map(move |n| // move is the keyword for moving variables into closure scope.
(n.clone(), id)
)