此问题已在此处有答案:
Calling a generic async function with a (mutably) borrowed argument(1个答案)
4天前关闭。
我正在尝试编写一个函数,它接受一个指向一个函数的指针,该函数执行嵌套在事务中的一些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
+执行方法(例如返回一行、多行、无...)。它应该使用查询函数中定义的方法执行查询,该方法嵌套在设置然后重置用户角色的事务中。
2条答案
按热度按时间omhiaaxx1#
找到了一个使用async traits的方法。
使用实际的sqlx类型显示:
8ehkhllq2#
问题在于不能用参数的生命周期来标记查询函数的输出。做这样的事情会很好。
但这是不成立的。我做了一个需要盒装trait对象的解决方案。(playground)
我还从
fn
升级到了FnOnce
,因为FnOnce
更通用。您可能需要FnMut
或Fn
。您可能还需要将Send
或Sync
添加到trait对象。请注意,按照常规的生存期规则,完全不可能将生成的future放入tokio::spawn
中。