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

SQLx中&mut *transaction与&mut transaction的区别解析

Rust中&mut *transaction与&mut transaction的区别解析

问题描述

我好奇示例代码里&mut *transaction与&mut transaction的区别,原以为transaction并非指针,但前者满足Executor trait约束,后者却不满足。如果把.execute(&mut *transaction)改为.execute(&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(())
    }
}

修改后触发的编译错误

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]

原因解析

1. 类型转换的本质:DerefMut特征的作用

sqlx::Transaction是一个封装了数据库连接和事务状态的包装类型,它实现了DerefMut特征——这个特征允许通过*操作符对实例进行解引用,获取它内部持有的PgConnection的可变引用。

  • &mut *transaction的执行逻辑:
    1. 先通过DerefMut对transaction解引用,得到&mut PgConnection类型的值
    2. 再对该值进行可变借用(这里是重新借用,最终类型仍为&mut PgConnection)
  • &mut transaction的类型则是&mut Transaction<'_, Postgres>,这是包装类型本身的可变引用

2. Executor trait的约束匹配

从编译错误信息可以看到,sqlx只为&mut PgConnection、连接池引用等实际执行SQL的底层类型实现了Executor trait,并没有为&mut Transaction实现该trait。因此:

  • &mut *transaction转换后的&mut PgConnection满足Executor约束,可以正常调用execute方法
  • &mut transaction的类型不满足约束,触发编译错误

3. 编译器区分二者的合理性

这完全符合Rust的静态类型设计原则:

  • Rust严格区分不同类型,包装类型Transaction和它内部的PgConnection是完全不同的类型
  • 解引用操作不会自动隐式触发在函数参数匹配中,必须显式写出&mut *transaction来告诉编译器需要通过DerefMut进行类型转换
  • 这种设计保证了类型安全,避免了隐式转换可能带来的意外行为

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.24 09:00:57