借钱不能搬出去
Cannot move out because of borrowing
我有以下 MWE:
use rusqlite::{Connection, Transaction };
fn main() {
let mut cn: Connection = Connection::open_in_memory().unwrap();
let tx: Transaction = cn.transaction().unwrap();
let mut stmt = tx.prepare("
INSERT INTO mytable (data) VALUES(1)
").unwrap();
stmt.execute([]).unwrap();
tx.commit().unwrap();
}
在我的IDE(vscode)中,它显示:
tx.prepare
显示错误
borrow of tx
occurs here
tx.commit();
显示错误
cannot move out of tx
because it is borrowed
签名:
pub fn prepare(&self, sql: &str) -> Result<Statement<'_>> {
self.db.borrow_mut().prepare(self, sql)
}
...
#[inline]
pub fn commit(mut self) -> Result<()> {
self.commit_()
}
我不明白为什么会显示这些错误。
tx.prepare
借用后,Transaction
创建并分配给 tx
的所有权是什么?
tx
仍然是 Transaction
的所有者吗?
- 当调用
tx.commit()
时,Transaction
应该属于tx
并且在调用.commit()
时可以安全移动,不是吗?
此外,确定 tx.prepare
的范围可以修复这些错误
use rusqlite::{Connection, Transaction };
fn main() {
let mut cn: Connection = Connection::open_in_memory().unwrap();
let tx: Transaction = cn.transaction().unwrap();
{
let mut stmt = tx.prepare("
INSERT INTO mytable (data) VALUES(1)
").unwrap();
stmt.execute([]).unwrap();
}
tx.commit().unwrap();
}
谢谢!
After tx.prepare
borrows, what is ownership the Transaction
created and assigned to tx
?
不确定我是否理解您的问题。借用不会改变所有权,它是从 所有者那里借用的。所以tx
拥有交易对象,stmt
借用它,因此所有权不能改变。
Is tx still the owner of the Transaction ?
是的。
When tx.commit()
is called, Transaction shoud be owned by tx and be safe to be moved when calling .commit()
, no ?
在大多数情况下是的,这里的问题是 Statement
不是一个“普通”类型,它实现了 Drop
这意味着它将(默认情况下)一直存在到它的 drop scope 除非它被显式删除(例如通过调用 drop(stmt)
)。然后,这将使用 Transaction::commit
进行编译,因为您无法移出“活动借用”。
您可以简单地通过安装与 Rusqlite 相匹配的类型方案来观察此行为:https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=32532b41467706d0d80756525a0f43fe
代码可以编译,但是如果您取消注释第 24 行 (impl Drop for …
),它会停止编译,并出现与此处相同的错误。
您的解决方案是:
- 如果 MRE 与实际代码匹配,则无需准备语句,这仅在您有多个查询时才有用
- 明确地
drop()
声明一旦你完成它
- 或者让它存在于自己的块中,因此它的放置范围比函数短
错误消息中给出了此原因:
14 | }
| - borrow might be used here, when `stmt` is dropped and runs the `Drop` code for type `Statement`
在 Transaction
上调用 prepare()
(通过自动取消引用汇集到 Connection
)会得到 Statement<'conn>
。换句话说,Statement
借用生命周期为 'conn
的基础 Connection
。 Connection
的借用依赖于 Transaction
,因为它是 Transaction
的自动解引用给了我们对 Connection
.
的借用
每当删除 Statement
时,它都会将 Connection
借用到 clean up behind it。这就是问题所在:您的 stmt
在范围末尾自动删除,在 tx.commit().unwrap()
之后。同时 .commit()
获得了 self
的所有权,因此 Transaction
被移走了。但是 Statement
的 Drop
实现需要 Transaction
的借用是存活的,所以它可以在 Connection
的借用上执行;所以发生错误。
您可以通过简单地引入一个内部范围来解决这个问题,或者在使用它之后手动drop(stmt)
。
我有以下 MWE:
use rusqlite::{Connection, Transaction };
fn main() {
let mut cn: Connection = Connection::open_in_memory().unwrap();
let tx: Transaction = cn.transaction().unwrap();
let mut stmt = tx.prepare("
INSERT INTO mytable (data) VALUES(1)
").unwrap();
stmt.execute([]).unwrap();
tx.commit().unwrap();
}
在我的IDE(vscode)中,它显示:
tx.prepare
显示错误
borrow of
tx
occurs here
tx.commit();
显示错误
cannot move out of
tx
because it is borrowed
签名:
pub fn prepare(&self, sql: &str) -> Result<Statement<'_>> {
self.db.borrow_mut().prepare(self, sql)
}
...
#[inline]
pub fn commit(mut self) -> Result<()> {
self.commit_()
}
我不明白为什么会显示这些错误。
tx.prepare
借用后,Transaction
创建并分配给tx
的所有权是什么?tx
仍然是Transaction
的所有者吗?- 当调用
tx.commit()
时,Transaction
应该属于tx
并且在调用.commit()
时可以安全移动,不是吗?
此外,确定 tx.prepare
的范围可以修复这些错误
use rusqlite::{Connection, Transaction };
fn main() {
let mut cn: Connection = Connection::open_in_memory().unwrap();
let tx: Transaction = cn.transaction().unwrap();
{
let mut stmt = tx.prepare("
INSERT INTO mytable (data) VALUES(1)
").unwrap();
stmt.execute([]).unwrap();
}
tx.commit().unwrap();
}
谢谢!
After
tx.prepare
borrows, what is ownership theTransaction
created and assigned totx
?
不确定我是否理解您的问题。借用不会改变所有权,它是从 所有者那里借用的。所以tx
拥有交易对象,stmt
借用它,因此所有权不能改变。
Is tx still the owner of the Transaction ?
是的。
When
tx.commit()
is called, Transaction shoud be owned by tx and be safe to be moved when calling.commit()
, no ?
在大多数情况下是的,这里的问题是 Statement
不是一个“普通”类型,它实现了 Drop
这意味着它将(默认情况下)一直存在到它的 drop scope 除非它被显式删除(例如通过调用 drop(stmt)
)。然后,这将使用 Transaction::commit
进行编译,因为您无法移出“活动借用”。
您可以简单地通过安装与 Rusqlite 相匹配的类型方案来观察此行为:https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=32532b41467706d0d80756525a0f43fe
代码可以编译,但是如果您取消注释第 24 行 (impl Drop for …
),它会停止编译,并出现与此处相同的错误。
您的解决方案是:
- 如果 MRE 与实际代码匹配,则无需准备语句,这仅在您有多个查询时才有用
- 明确地
drop()
声明一旦你完成它 - 或者让它存在于自己的块中,因此它的放置范围比函数短
错误消息中给出了此原因:
14 | }
| - borrow might be used here, when `stmt` is dropped and runs the `Drop` code for type `Statement`
在 Transaction
上调用 prepare()
(通过自动取消引用汇集到 Connection
)会得到 Statement<'conn>
。换句话说,Statement
借用生命周期为 'conn
的基础 Connection
。 Connection
的借用依赖于 Transaction
,因为它是 Transaction
的自动解引用给了我们对 Connection
.
每当删除 Statement
时,它都会将 Connection
借用到 clean up behind it。这就是问题所在:您的 stmt
在范围末尾自动删除,在 tx.commit().unwrap()
之后。同时 .commit()
获得了 self
的所有权,因此 Transaction
被移走了。但是 Statement
的 Drop
实现需要 Transaction
的借用是存活的,所以它可以在 Connection
的借用上执行;所以发生错误。
您可以通过简单地引入一个内部范围来解决这个问题,或者在使用它之后手动drop(stmt)
。