Eu tenho o seguinte código Rust
use std::error::Error;
#[derive(Debug)]
enum MyEnum {
First,
Second,
}
fn do_something(index: usize, m: &MyEnum) {
eprintln!("do_something: {} {:?}", index, m);
}
async fn test() -> Result<(), Box<dyn Error>> {
let myvec = vec![MyEnum::First, MyEnum::Second];
let c = String::from("cap");
let futures = myvec.iter().enumerate().map(|(index, el)| async {
eprintln!("Element: {}", &c);
do_something(index, el);
});
futures::future::join_all(futures).await;
Ok(())
}
#[tokio::main]
async fn main() -> Result<(), Box<dyn Error>> {
test().await?;
Ok(())
}
O compilador reclama que:
error[E0373]: async block may outlive the current function, but it borrows `index`, which is owned by the current function
--> src/main.rs:17:62
|
17 | let futures = myvec.iter().enumerate().map(|(index, el)| async {
| ^^^^^ may outlive borrowed value `index`
18 | eprintln!("Element: {}", &c);
19 | do_something(index, el);
| ----- `index` is borrowed here
|
Por que não está reclamando da el
variável?
E como consertar esse código? Eu gostaria de continuar usando o iterador e não for
o loop. Eu posso mudar outras partes do código, por exemplo, do_something()
posso ter protótipos diferentes.
Coloquei a c
variável aqui para proibir a solução fácil com async move {...}
. A string c
não deve ser movida.
Sem enumerate()
(e sem index
) funciona. Eu esperaria que index
(que tem usize
tipo) fosse facilmente copiável.
Esse é exatamente o problema, porque
usize
é cópia, para que ela se mova o compilador só precisa capturar uma referência compartilhada, ele pode simplesmente copiar os bytes quando precisar de um valor. Ele usará o tipo mais fraco de captura que puder, primeiro&
, depois&mut
e somente se isso não funcionar, ele se moverá.O problema é que
index
é um local para o fechamento , que desaparece quando retorna no futuro.el
não tem o mesmo problema porque é uma referência ao externomyvec
que é propriedade detest
, que vive o suficiente, portanto, qualquer referência a ele também pode viver o suficiente.Para consertar, basta aplicar a "solução fácil" que você encontrou. Qualquer captura que você não queira mover, você pode simplesmente sombrear 1 com o tipo de encadernação desejado (
&
ou&mut
):1 Claro que você não precisa sombreá-lo, mas sombreá-lo permite que você não se preocupe com um novo nome e é bastante idiomático aqui.