Error al utilizar async/await en Rust

Publicado por Brisa
hace 5 meses

Hola a todos,

Estoy experimentando con la programación asíncrona en Rust utilizando el modificador async y la palabra clave await. Sin embargo, estoy teniendo algunos problemas al tratar de compilar mi código. Aquí está el código que estoy utilizando:

use std::future::Future;
use std::pin::Pin;
use std::task::{Context, Poll};

async fn my_async_function() -> i32 {
    // Alguna lógica asíncrona aquí
    return 42;
}

struct MyFuture {
    value: Option<i32>,
}

impl Future for MyFuture {
    type Output = i32;

    fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
        if let Some(value) = self.value.take() {
            Poll::Ready(value)
        } else {
            self.value = Some(cx.waker().wake_by_ref().clone());
            Poll::Pending
        }
    }
}

async fn my_async_function_that_uses_future() {
    let future = MyFuture { value: Some(42) };
    let result = await!(future);
    println!("Resultado: {}", result);
}

#[tokio::main]
async fn main() {
    await!(my_async_function_that_uses_future()).await;
}

Cuando intento compilar este código, obtengo el siguiente error:

error[E0658]: async block may outlive the current function, but it borrows `*self` which is owned by the current function
  --> src/main.rs:20:13
   |
18 | impl Future for MyFuture {
   | --------------- `self` is borrowed here
19 |     type Output = i32;
20 |     fn poll<'a>(self: Pin<&'a mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
   |             ^^^^              --- `self` is borrowed here
   |             |
   |             borrowed value does not live long enough
...
23 |             self.value = Some(cx.waker().wake_by_ref().clone());
   |             ------- `self` is borrowed here
...
26 |     }
   |     - returned value dropped here while still borrowed
...
35 | }
   | - borrowed value needs to live until here
...
42 | }
   | - `self` dropped here while still borrowed

error: aborting due to previous error

For more information about this error, try `rustc --explain E0658`.
error: could not compile `async_await_example`

¿Qué puede estar causando este error y cómo puedo solucionarlo?

¡Gracias de antemano!

Rust async await
Respuesta de Gordon Shumway
hace 5 meses

¡Hola Brisa!

Tengo algunas observaciones sobre tu código que creo que podrían ayudarte a solucionar los problemas:

  1. Primero, parece que estás intentando utilizar una antigua sintaxis de await (es decir, await!(future)). En las versiones más recientes de Rust, solo necesitas usar .await para esperar una Future. Así que deberías cambiar await!(future) por future.await.

  2. En la función poll estás haciendo un wake_by_ref() y luego asignando algo a self.value. Esto no es correcto y es la causa del error E0658. En cambio, si quieres crear una Future sencilla que retorne Poll::Ready cuando haya un valor, no necesitas interactuar con el Context ni con el Waker.

  3. En Rust, la función main no necesita ser una función async para usar .await, puedes utilizar la macro #[tokio::main] directamente y dentro de la función main, simplemente llamas a las funciones asíncronas y aplicas el .await.

Con esas correcciones, el código debería verse algo así:

use std::future::Future;
use std::pin::Pin;
use std::task::{Context, Poll};

async fn my_async_function() -> i32 {
    // Alguna lógica asíncrona aquí
    42 // En Rust, no es necesario usar `return` para el valor final de una función.
}

struct MyFuture {
    value: Option<i32>,
}

impl Future for MyFuture {
    type Output = i32;

    fn poll(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<Self::Output> {
        // No necesitas interactuar con el contexto ni el waker aquí.
        if let Some(value) = self.value.take() {
            Poll::Ready(value)
        } else {
            // En una implementación real, aquí manejarías el caso donde aún no hay un valor disponible.
            // Pero, por simplicidad, vamos a asumir que siempre hay un valor y siempre está listo.
            Poll::Pending
        }
    }
}

async fn my_async_function_that_uses_future() -> i32 { // Hacemos que retorne i32
    let mut future = MyFuture { value: Some(42) };
    let result = future.await;
    println!("Resultado: {}", result);
    result // Retornamos el resultado
}

#[tokio::main]
async fn main() {
    let _result = my_async_function_that_uses_future().await;
}

Las correcciones son:

  • Usar .await en lugar de await!(), que es obsoleto.
  • Cambié la función poll para quitar la lógica incorrecta del waker.
  • Actualicé la función main para usar .await directamente sin necesidad de hacerlo sobre await!().

Prueba con esos cambios y deberías poder compilar y ejecutar tu código. ¡Espero que esto te ayude! Si tienes más dudas, ¡aquí estoy!