I have the following Rust code using rust-postgres with the intention of committing a transaction after my struct goes out of scope
struct SqlTransaction<'a> {
connection: &'a Connection,
transaction: Transaction<'a>,
}
impl<'a> Drop for SqlTransaction<'a> {
fn drop(&mut self) {
let result = self.transaction.commit();
match result {
Ok(_) => print!("herp"),
Error => print!("lol"),
}
}
}
The compiler complains about the commit()
line with the following message
cannot move out of type `SqlTransaction<'a>`, which defines the `Drop` trait [E0509]at line 12 col 22
What is happening and how can I fix that?
The Transaction::commit
method consumes the transaction:
pub fn commit(self) -> Result<()> {
self.set_commit();
self.finish()
}
If you were able to call commit
, then the value of self
would be in some inconsistent state, because what would the value of self.transaction
be? It's been moved out!
If the type didn't implement Drop
, this wouldn't be a problem, as the compiler would just drop all the other pieces of the struct. However, since it implements Drop
, then you can never pull apart the struct because then Drop
could not run! This even applies when you are inside the Drop
implementation itself.
If you actually needed to do this, you'd have to have transaction
be some type that you could easily replace. An Option
is a good choice, as you can use take
to replace it with a None
.
In the specific case of the Transaction
, you don't have to do anything special. While a Transaction
normally rolls back on drop, you can call Transaction::set_commit
so that it commits on drop.