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

Rust中async_trait与借用问题:`collection`生命周期报错求助

Rust async_trait 与借用生命周期问题排查

依赖项

[dependencies]
mongodb = { version = "2.3.1"}
tokio = "1.22.0"
twilio-openapi = "1.0.0"
async-trait = "0.1.58"
futures = "0.3.25"

Repository Trait 定义

基于async_trait实现的数据访问仓库Trait:

use std::pin::Pin;

use async_trait::async_trait;
use futures::Future;
use mongodb::{bson::Document, error::Error, options::FindOneOptions, Client};

pub mod notification_settings;

#[async_trait]
pub trait Repository<'a> {
    fn with_client(client: &'a mut &Client) -> Self;
    async fn find_one<'b>(
        self,
        filter: Document,
        find_one_options: FindOneOptions,
    ) -> Pin<Box<(dyn Future<Output = Result<Option<Document>, Error>> + Send + 'b)>>;
}

对async_trait要求返回Pin<Box<dyn Future<Output = X> + Send + 'b>>的原因及替代方案存在疑问。

结构体实现

实现上述Trait的NotificationSettingsRepository:

use std::{marker::Send, pin::Pin};

use async_trait::async_trait;
use futures::Future;
use mongodb::{bson::Document, error::Error, options::FindOneOptions, Client};

pub struct NotificationSettingsRepository<'a> {
    pub(crate) client: &'a Client,
}

#[async_trait]
impl<'a> super::Repository<'a> for NotificationSettingsRepository<'a> {
    fn with_client(client: &'a mut &Client) -> Self {
        NotificationSettingsRepository { client: client }
    }

    async fn find_one<'b>(
        self,
        filter: Document,
        find_one_options: FindOneOptions,
    ) -> Pin<Box<(dyn Future<Output = Result<Option<Document>, Error>> + Send + 'b)>> {
        let collection = self
            .client
            .database("Occasionally")
            .collection::<Document>("NotificationSettings");

        let document = collection.find_one(filter, find_one_options);

        Box::pin(async { document.await })
    }
}

编译错误信息

在collection.find_one(filter, find_one_options);处触发报错:

`collection` does not live long enough
borrowed value does not live long enoughrustcClick for full compiler diagnostic
notification_settings.rs(30, 5): `collection` dropped here while still borrowed
notification_settings.rs(17, 23): lifetime `'b` defined here
notification_settings.rs(21, 10): type annotation requires that `collection` is borrowed for `'b`

已知问题源于find_one通过&self借用collection,但尝试用async {}包装等操作无效,寻求解决办法。


问题分析与解决方案

错误根源

  • 局部变量collection在函数执行完毕后会被销毁,但find_one返回的Future持有对它的引用,要求其生命周期至少覆盖'b,这一约束无法满足。
  • 对async_trait的使用存在误区:默认情况下async_trait会自动处理Future的生命周期,手动指定返回Pin<Box<dyn Future<...>>>反而引入了生命周期冲突。

修正方案

  1. 简化Trait定义,让async_trait自动处理异步返回值:
#[async_trait]
pub trait Repository<'a> {
    fn with_client(client: &'a Client) -> Self;
    async fn find_one(
        &self,
        filter: Document,
        find_one_options: Option<FindOneOptions>,
    ) -> Result<Option<Document>, Error>;
}
  1. 修正结构体实现:
#[async_trait]
impl<'a> super::Repository<'a> for NotificationSettingsRepository<'a> {
    fn with_client(client: &'a Client) -> Self {
        NotificationSettingsRepository { client }
    }

    async fn find_one(
        &self,
        filter: Document,
        find_one_options: Option<FindOneOptions>,
    ) -> Result<Option<Document>, Error> {
        let collection = self
            .client
            .database("Occasionally")
            .collection::<Document>("NotificationSettings");
        
        collection.find_one(filter, find_one_options).await
    }
}

关键调整点

  • 移除Trait中find_one手动指定的Future返回类型,交由async_trait自动处理,避免生命周期手动管理混乱。
  • 将find_one的参数从self改为&self,允许重复使用Repository实例,而非每次调用就消耗实例。
  • 简化with_client的参数类型,直接接受&'a Client,去掉冗余的双重引用&'a mut &Client。
  • 将FindOneOptions改为Option<FindOneOptions>,更符合MongoDB Rust驱动的使用习惯(允许不传参数)。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.11 01:31:08