¿Por qué el compilador está diciendo que la variable se ha descartado mientras todavía está prestada si el prestatario ya se ha descartado?
Tengo una pregunta sobre las duraciones de vida. Tengo el siguiente código:
async move {
let futures = FuturesUnordered::new();
let subscriptions = database.get_subscribers_for(&msg).await?;
for notifier in notifiers.iter() {
futures.push(notifier.notify(&msg, &subscriptions));
}
let results = futures.collect::<><result<(), ()="">>>().await;
results
.into_iter()
.filter(Result::is_err)
.for_each(|result| error!("Error al enviar la notificación: {}", result.unwrap_err()));
Ok(())
}
Firma de notify:
async fn notify(&self, msg: &Notification, subs: &[Subscriptions]) -> Result<(), ()>
Estoy obteniendo un error que dice que subscriptions
podría no vivir el tiempo suficiente y que subscriptions
aún puede ser prestado cuando se descarte. ¿Cómo puede ser si al recopilar desde los futures
, se toma el valor de los futuros y luego llamo a into_iter
, que consume todas las entradas?
Entonces, básicamente, los futures
se descartarán antes que subscriptions
. ¿Lo estoy entendiendo mal?
Si configuro el código de esta manera, forzando a que los futuros estén en un bloque separado, compila:
async move {
let subscriptions = database.get_subscribers_for(&msg).await?;
{
let futures = FuturesUnordered::new();
for notifier in notifiers.iter() {
futures.push(notifier.notify(&msg, &subscriptions));
}
let results = futures.collect::<><result<(), ()="">>>().await;
results
.into_iter()
.filter(Result::is_err)
.for_each(|result| error!("Error al enviar la notificación: {}", result.unwrap_err()));
}
Ok(())
}
Mensaje del compilador:
error[E0597]: `subscriptions` no vive lo suficiente
</result<(),></result<(),>
--> src/notification/mod.rs:57:52
|
57 | futures.push(notifier.notify(&msg, &subscriptions));
| ^^^^^^^^^^^^^^ el valor prestado no vive lo suficiente
...
65 | })
| -
| |
| `subscriptions` se descarta aquí mientras aún está prestado
| el préstamo podría ser utilizado aquí, cuando `futures` se descarte y se ejecute el código `Drop` para el tipo `FuturesUnordered`
|
= nota: los valores en un ámbito se descartan en el orden opuesto a su definición
davy.ai
El problema aquí es que el método
notify
está tomando prestado el segmentosubscriptions
, pero el vectorfutures
y su contenido podrían sobrevivirlo. Por eso, el compilador se queja de quesubscriptions
podría no vivir el tiempo suficiente.Aunque estés consumiendo el vector
futures
al llamar ainto_iter
, el vector y su contenido se eliminan cuando el bloqueasync move
retorna. Sin embargo, el métodonotify
podría seguir teniendo una referencia asubscriptions
cuando eso sucede, de ahí el error.Al mover el vector
futures
a un bloque separado, te aseguras de que él y su contenido se eliminen antes quesubscriptions
. De esta manera, el compilador está contento porque puede garantizar quesubscriptions
vivirá el tiempo suficiente para el métodonotify
.Así que, para responder a tu pregunta, no lo estás entendiendo mal. La llamada a
into_iter
consume el vectorfutures
y su contenido, pero eso no significa necesariamente que todos los préstamos se liberen inmediatamente. Mover el vectorfutures
a un bloque separado es una buena manera de asegurarse de que todo se elimine en el orden correcto.