我正在尝试编写一个函数,该函数接受一个指向函数的指针,该函数执行嵌套在事务中的一些 SQL 查询。我已经遇到这个错误一天了,我不知道如何解决它。
最小可重现示例
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
进行查询,因此结构为 Query
和Transaction
.
我希望能够写出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/