Llamando a una función asíncrona genérica con un argumento prestado (mutablemente).
Ejemplo mínimo de mi problema.
use std::future::Future;
async fn call_changer<'a, F, Fut>(changer: F)
where
F: FnOnce(&'a mut i32) -> Fut,
Fut: Future<output =="" ()=""> + 'a,
{
let mut i = 0;
changer(&mut i).await; // error 1
dbg!(i); // error 2
}
#[tokio::main]
async fn main() {
call_changer(|i| async move {
*i = 100;
})
.await;
}
Esto provoca dos errores relacionados, consulte rust playground para obtener una salida detallada:
- El préstamo no vive el tiempo suficiente porque
i
se descarta al final del cuerpo decall_changer
. i
no se puede utilizar después del await porque todavía se está prestando de forma mutable.
Me sorprende un poco ambos errores, entiendo por qué el retorno Future
de F
necesita tener la misma duración ('a
) que su préstamo (sección relevante del libro async). Sin embargo, según la misma referencia, el préstamo debería finalizar tan pronto como llamo al await en el resultado de changer
, lo cual claramente no sucede o no tendría esos errores. Reestructurar este ejemplo a algo como el libro, donde la función changer
no se pasa como parámetro sino que se llama directamente, funciona como se espera.
¿Qué está sucediendo aquí y puedo hacer algo al respecto? Reemplazar &mut
con una construcción Rc<refcell<_>>
funciona como se espera, pero si es posible, me gustaría evitar eso.</refcell<_>
davy.ai
El problema con este código es que el préstamo mutable de
i
se mantiene durante toda la duración del futuroFut
, incluso después de que se haya completado la palabra claveawait
. Esto se debe a que el préstamo se realiza en el argumento dechanger
y es capturado por el futuro devuelto porchanger
.Para solucionar esto, puedes utilizar
Pin<><dyn></dyn><output =="" ()=""> + 'a>>
en lugar deFut
como tipo de retorno dechanger
, lo cual permitirá que el futuro se fije en el marco de la pila y se descarte inmediatamente después de la palabra claveawait
. Aquí está el código modificado:Esto debería solucionar los problemas de préstamo y permitir que el código se compile y se ejecute como se espera.