我很好奇在我的示例中
&mut *transaction
和 &mut transaction
之间有什么区别,因为我不认为 transaction
是一个开始的指针,但由于某种原因 &mut *transaction
满足特征约束,而 &mut transaction
没有。
这是我的工作代码:
use sqlx::{PgPool, Transaction, Executor};
use chrono::{DateTime, Utc};
pub struct SimpleDbClient {
db: PgPool,
}
pub trait AddCharacterEntries {
async fn insert_character_entries(&self, timestamp: DateTime<Utc>, char_values: Vec<(char, i32)>) -> sqlx::Result<()>;
}
impl AddCharacterEntries for SimpleDbClient {
async fn insert_character_entries(&self, timestamp: DateTime<Utc>, char_values: Vec<(char, i32)>) -> sqlx::Result<()> {
let mut transaction = self.db.begin().await?;
for (character, ascii_value) in char_values {
sqlx::query!(
r#"
INSERT INTO character_log (timestamp, character, ascii_value)
VALUES ($1, $2, $3)
"#,
timestamp,
character as char,
ascii_value
)
.execute(&mut *transaction)
.await?;
}
transaction.commit().await?;
Ok(())
}
}
如果我将上面的内容更改为
.execute(&mut transaction)
,我会收到此错误:
rustc: the trait bound `&mut sqlx::Transaction<'_, sqlx::Postgres>: sqlx::Executor<'_>` is not satisfied
the following other types implement trait `sqlx::Executor<'c>`:
<&'c mut sqlx::PgConnection as sqlx::Executor<'c>>
<&'c mut sqlx::sqlx_postgres::PgListener as sqlx::Executor<'c>>
<&'c mut sqlx::AnyConnection as sqlx::Executor<'c>>
<&sqlx::Pool<DB> as sqlx::Executor<'p>> [E0277]
rustc: required by a bound introduced by this call [E0277]
这是否归结为进行某种类型转换?很好奇这是否会被视为一种限制,或者编译器认为这两个表达式是不同的对象实际上是否有意义。
我不认为
是一个开始的指针transaction
Transaction
实现 Deref
和 DerefMut
。当您尝试对实现 Deref
的值调用方法时,Rust 可以通过这些特征自动取消引用,但您也可以使用 *
运算符显式取消引用。然后 &mut
获取对此值的引用,在本例中是 PgConnection
。
transaction
是类型 Transaction<Postgres>
。*transaction
是类型 PgConnection
。&mut *transaction
是类型 &mut PgConnection
。因为 sqlx 实现了这些特征,所以这允许您透明地在
Transaction
值上调用底层数据库连接的任何(非消耗)方法,类似于透明地执行切片类型的任何(非消耗)方法在Vec
。
请注意,在使用实现
&*
(也可能是 &mut *
)的类型时,重借(Deref
和 DerefMut
)是常见模式。一些例子:
some_vec
是 Vec<T>
,&*some_vec
会给你一个 &[T]
。some_box
是 Box<T>
,&*some_box
会给你一个 &T
。这里有几个活动部件。您没有指定您正在使用的
sqlx
版本,但从您收到的错误来看,我认为这是 0.7.x
,因此我的答案将针对此版本。
Query::execute
将 Executor
作为参数。请注意 Executor
文档中的以下部分:
针对以下情况实施:
- &泳池
- &mut 连接
和Executor
的Transaction
隐含已被删除,因为如果不完全重写PoolConnection
特性,它们就无法存在于新的 crate 架构中。要修复此损坏,只需在需要Executor
的位置添加取消引用,因为它们都取消引用仍将实现它的内部连接类型:impl Executor
->&mut transaction
&mut *transaction
->&mut connection
&mut *connection
Transaction
实现了Deref<Target = <DB as Database>::Connection>
,你必须取消引用并重新借用它(即创建&mut *transaction
),将其传递给execute
。