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

如何在Rust中传递SQLX的&mut Executor trait作为泛型函数参数

泛化SQLX代码以支持Executor trait并允许多次调用

问题背景

现有SQLX代码使用具体的&mut SqliteConnection作为参数时,process和process_twice均可正常工作(process_twice会调用process两次)。但将参数泛化为满足E: Executor约束的类型后,由于Executor trait的实现(如&mut SqliteConnection)不可复制,process_twice无法实现多次调用process的逻辑。

解决方案

核心思路是通过高阶生命周期约束和可变引用参数,让泛型类型支持多次借用,从而适配Executor trait的要求:

  1. 调整process的泛型签名,接收可变引用形式的参数,并约束参数类型在任意生命周期下都能实现Executor;
  2. 对process_twice应用相同的泛型约束,确保可以多次传递参数调用process。

完整泛化代码

// [dependencies]
// anyhow = "1.0"
// futures = "0.3"
// sqlx = { version = "0.6", features = [ "sqlite", "runtime-tokio-native-tls"] }
// tokio = { version = "1.28.2", features = ["macros"] }
//
// //// TO RUN, must set env var:
// DATABASE_URL='sqlite::memory:' cargo run

use futures::TryStreamExt;
use sqlx::SqliteConnection;
use sqlx::{query, Connection};

#[tokio::main]
async fn main() -> anyhow::Result<()> {
    let mut conn = SqliteConnection::connect("sqlite::memory:").await?;
    process(&mut conn).await?;
    process_twice(&mut conn).await?;
    Ok(())
}

async fn process<E>(conn: &mut E) -> anyhow::Result<()>
where
    E: for<'a> sqlx::Executor<'a, Database = sqlx::Sqlite>,
{
    let sql = query!("SELECT name FROM sqlite_master");
    let mut rows = sql.fetch(conn);
    while let Some(row) = rows.try_next().await? {
        println!("{row:?}")
    }
    Ok(())
}

async fn process_twice<E>(conn: &mut E) -> anyhow::Result<()>
where
    E: for<'a> sqlx::Executor<'a, Database = sqlx::Sqlite>,
{
    process(conn).await?;
    process(conn).await?;
    Ok(())
}

原理说明

  • 高阶生命周期for<'a>:确保参数类型E在任意生命周期下都能实现Executor<'a>,适配SQLX对Executor生命周期的要求;
  • 可变引用参数&mut E:每次调用process时,只是对原可变引用进行重新借用,不会消耗原参数,因此可以在process_twice中多次传递调用。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.20 05:27:44