You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Rust中如何在poll方法内调用带非静态引用的async函数?

问题:实现Future trait时的生命周期错误

我在实现Future trait时遇到了障碍。需要在自己的poll方法中调用一个第三方库的async函数,该函数仅接受&str参数,定义如下:

async fn make_query(query: &str) -> i32 {
    // Magic happens
    5
}

无法修改这个函数的签名来获取参数所有权。

我定义了持有String的Executor结构体,希望调用make_query时引用它,并尝试为该结构体实现Future trait:

struct Executor {
    query: String,
    future: Mutex<Option<Pin<Box<dyn Future<Output = i32>>>>>
}

impl Future for Executor {
    type Output = i32;

    fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
        let mut lock = self.future.lock().unwrap();

        if let None = *lock {
            // 此处出现错误
            *lock = Some(Box::pin(make_query(&self.query)))
        }

        let future = lock.as_mut().unwrap();
        pin!(future).poll(cx)
    }
}

预期可以通过.await Executor自动执行查询:

#[tokio::main]
async fn main() {
    let result = Executor {
        query: "foo".to_string(),
        future: Mutex::new(None)
    }.await;

    println!("Result is {result}");
}

但出现生命周期错误,提示Mutex要求传入的引用必须是'static,错误信息如下:

error: lifetime may not live long enough
  --> src/main.rs:23:26
   |
16 |     fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
   |                       - let's call the lifetime of this reference `'1`
...
23 |             *lock = Some(Box::pin(make_query(&self.query)))
   |                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cast requires that `'1` must outlive `'static`

error[E0597]: `self` does not live long enough
  --> src/main.rs:23:47
   |
16 |     fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
   |             ---- binding `self` declared here
...
23 |             *lock = Some(Box::pin(make_query(&self.query)))
   |                          ---------------------^^^^--------
   |                          |                    |
   |                          |                    borrowed value does not live long enough
   |                          cast requires that `self` is borrowed for `'static`
...
29 |     }
   |     - `self` dropped here while still borrowed

无法修改poll的函数签名,需要解决这个生命周期问题,或者找到更合适的实现方式。

解决方案

移除结构体中的future字段,简化Executor定义:

struct Executor {
    query: String
}

不再直接实现Future trait,转而实现IntoFuture trait(使用.await时会隐式调用该trait)。通过async move {}转移Executor的所有权,这样就可以安全地引用内部的query字符串:

注意:当前type IntoFuture = impl Future是不稳定特性,因此使用Pin<Box<dyn Future>>作为返回类型

impl IntoFuture for Executor {
    type Output = i32;
    type IntoFuture = Pin<Box<dyn Future<Output = Self::Output>>>;

    fn into_future(self) -> Self::IntoFuture {
        Box::pin(async move {
            make_query(&self.query).await
        })
    }
}

现在可以正常对Executor调用.await:

#[tokio::main] 
async fn main() {
    let res = Executor {
        query: "foo".into()
    }.await;

    println!("Result is {res}"); // 5
}

内容的提问来源于stack exchange,提问作者hjpev

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.16 17:43:04