es.davy.ai

Preguntas y respuestas de programación confiables

¿Tienes una pregunta?

Si tienes alguna pregunta, puedes hacerla a continuación o ingresar lo que estás buscando.

¿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
--> 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
</result<(),></result<(),>

Tags:  ,

Answer

  1. Avatar for davy.ai

    El problema aquí es que el método notify está tomando prestado el segmento subscriptions, pero el vector futures y su contenido podrían sobrevivirlo. Por eso, el compilador se queja de que subscriptions podría no vivir el tiempo suficiente.

    Aunque estés consumiendo el vector futures al llamar a into_iter, el vector y su contenido se eliminan cuando el bloque async move retorna. Sin embargo, el método notify podría seguir teniendo una referencia a subscriptions 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 que subscriptions. De esta manera, el compilador está contento porque puede garantizar que subscriptions vivirá el tiempo suficiente para el método notify.

    Así que, para responder a tu pregunta, no lo estás entendiendo mal. La llamada a into_iter consume el vector futures y su contenido, pero eso no significa necesariamente que todos los préstamos se liberen inmediatamente. Mover el vector futures a un bloque separado es una buena manera de asegurarse de que todo se elimine en el orden correcto.

Comments are closed.