asynchronous - 当内部可变的生命周期较短时,如何通过函数指针传递可变引用?

标签 asynchronous rust function-pointers lifetime rust-sqlx

我正在尝试编写一个函数,该函数接受一个指向函数的指针,该函数执行嵌套在事务中的一些 SQL 查询。我已经遇到这个错误一天了,我不知道如何解决它。

最小可重现示例

Rust Playground Link

use core::future::Future;

// Allows execution of a set of queries.
struct Transaction(pub usize);
// A single SQL query string.
struct Query(pub &'static str);

impl Query {
    // Execute the query without returning anything.
    pub async fn execute_without_return(&self, tx: &mut Transaction) {
        tx.0 += 1;
        println!("{}", self.0);
    }
    
    // Execute the query and return a result.
    pub async fn execute_with_return(&self, tx: &mut Transaction) -> usize {
        tx.0 += 1;
        println!("{}", self.0);
        return 123;
    }
}

// Execute some query between two other queries to set and reset the user role.
async fn query_as_user<Fut>(query_fn: fn(&mut Transaction) -> Fut) -> usize 
where
  Fut: Future<Output = usize>
{
    let mut tx = Transaction(0);
    Query("SET ROLE user;").execute_without_return(&mut tx).await;
    let result = query_fn(&mut tx).await;
    Query("RESET ROLE;").execute_without_return(&mut tx).await;
    result
}

async fn select_all(tx: &mut Transaction) -> usize {
    Query("SELECT * FROM table;").execute_with_return(tx).await
}

#[tokio::main]
async fn main() {
    let res = query_as_user(select_all).await;
    println!("\nResult: {}", res)
}

如果按原样运行代码,它将显示错误:

error[E0308]: mismatched types
  --> src/main.rs:41:29
   |
41 |     let res = query_as_user(select_all).await;
   |               ------------- ^^^^^^^^^^ one type is more general than the other
   |               |
   |               arguments to this function are incorrect
   |
   = note: expected fn pointer `for<'a> fn(&'a mut Transaction) -> _`
                 found fn item `for<'a> fn(&'a mut Transaction) -> impl Future<Output = usize> {select_all}`
   = note: when the arguments and return types match, functions can be coerced to function pointers
note: function defined here
  --> src/main.rs:24:10
   |
24 | async fn query_as_user<Fut>(query_fn: fn(&mut Transaction) -> Fut) -> usize 
   |          ^^^^^^^^^^^^^      -------------------------------------

For more information about this error, try `rustc --explain E0308`.
error: could not compile `playground` (bin "playground") due to previous error

通过一些生命周期注释的欺骗,我会得到一个不同的错误 - 这是:

error[E0521]: borrowed data escapes outside of async closure
error[E0499]: cannot borrow `tx` as mutable more than once at a time

此错误来自非玩具程序,但本质上指向 let result = query_fn(&mut tx).await;并声称对 tx 的可变引用无效。

在实际程序中,我也试图使返回类型变得通用,但这是问题的核心。

注意:我正在使用sqlx进行查询,因此结构为 QueryTransaction .

我希望能够写出query_as_user函数接受任何 Query + 执行方法(例如返回一行、多行、什么都不返回...)。它应该使用查询函数中定义的方法执行查询,该方法嵌套在设置然后重置用户角色的事务中。

最佳答案

找到了一种使用异步特征来执行此操作的方法。

使用实际 sqlx 类型显示:

trait AsUserQueryFn<Args, Out> {
    async fn call(
        &mut self,
        tx: &mut Transaction<'_, Postgres>,
        args: Args,
    ) -> Result<Out, sqlx::Error>;
}

async fn execute_user_level_query<'a, Args, Out>(
    &'a self,
    as_user: UserTableRow,
    input: Args,
    mut execution_fn: impl AsUserQueryFn<Args, Out>,
) -> Result<Out, UserLevelQueryError> {
  ...
}

关于asynchronous - 当内部可变的生命周期较短时,如何通过函数指针传递可变引用?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/76543585/

相关文章:

java - Android 异步任务重用

c# - 在 Sitecore Controller 渲染中启用异步

c - int (* f [])(); 和有什么区别和 int f[]();

c - 函数之间的文件指针上的 SegmentFault

c - 取消引用 C 中的函数指针以访问 CODE 内存

ios - Swift 中带有 Firestore 的完成处理程序的替代方案

Java play框架 对同一对象的异步操作

rust - 如何在 BTreeMap/BTreeSet 中找到下一个较小的键?

rust - 为什么不能在同一结构中存储值和对该值的引用?

macros - 宏可以将数组/向量扩展为多个索引参数吗?