如何在 Rust 的同一个结构中存储 rusqlite Connection 和 Statement 对象? [英] How to store rusqlite Connection and Statement objects in the same struct in Rust?
问题描述
我正在开发我的第一个 Rust 程序,并且与 Rust 所有权语义发生冲突.我已经声明了一个 struct
,它将封装一个 SQLite 数据库连接,因此它维护一个 Connection
成员.出于性能原因,我还想保留一个准备好的语句,由 Statement
类型表示.这是我的代码的简化版本:
I'm working on my first Rust program and have run afoul of Rust ownership semantics. I have declared a struct
which will encapsulate a SQLite database connection so it maintains a Connection
member. For performance reasons, I also want to keep a prepared statement, represented by the Statement
type. Here is a simplified version of my code:
extern crate rusqlite; // 0.14.0
use rusqlite::{Connection, Statement};
pub struct Foo<'a> {
conn: Connection,
statement: Statement<'a>,
}
impl<'a> Foo<'a> {
pub fn new() -> Foo<'a> {
let conn = Connection::open(&":memory:").unwrap();
let statement = conn
.prepare("INSERT INTO Foo(name, hash) VALUES($1, $2)")
.unwrap();
Foo { conn, statement }
}
}
我试图通过将 conn
变量存储在 Foo
的成员中来将其所有权转移给被调用者,但是当我尝试编译此代码时它失败了:
I'm trying to transfer ownership of the conn
variable to the callee by storing it in a member of Foo
, but when I attempt to compile this code it fails:
error[E0597]: `conn` does not live long enough
--> src/main.rs:13:25
|
13 | let statement = conn
| ^^^^ borrowed value does not live long enough
...
17 | }
| - borrowed value only lives until here
|
note: borrowed value must be valid for the lifetime 'a as defined on the impl at 10:6...
--> src/main.rs:10:6
|
10 | impl<'a> Foo<'a> {
| ^^
出于某种原因,rusqlite::Connection
类型没有生命周期参数,因此我无法将其生命周期与 Statement
的生命周期明确绑定实例.
For some reason, the rusqlite::Connection
type doesn't take a lifetime parameter, so I'm unable to explicitly tie its lifetime to that of the Statement
instance.
我错过了什么?这种封装是一种很常见的模式,我肯定我遗漏了一些东西.
What am I missing? This kind of encapsulation is a very common pattern, I'm sure I'm missing something.
推荐答案
我们来看看 Connection::prepare
:
Let's look at Connection::prepare
:
pub fn prepare<'a>(&'a self, sql: &str) -> Result<Statement<'a>>
如果我们忽略Result
(这只是意味着这个函数可能会失败),这意味着返回一个Statement
,它的存活时间不超过Connection
调用了 prepare
".这可能是由于 Statement
包含对 Connection
的引用.
If we ignore the Result
(which just means that this function can fail), this means "return a Statement
that can live no longer than the Connection
that prepare
was called on". This is likely due to the Statement
containing a reference to the Connection
.
但是,如果您有对项目的引用,则不能再移动该项目,因为该引用将失效.使用那个无效的引用会导致内存不安全,所以它被阻止了.
However, if you have a reference to an item, then you can no longer move the item because the reference would be invalidated. Using that invalid reference would lead to memory unsafety, so it's prevented.
基本上,您需要在代码中反映这些对象的生命周期和所有权,因此您不能将 Connection
和 Statement
捆绑在同一结构中.相反,一个可以引用另一个.
Basically, you need to mirror the lifetimes and ownership of these objects in your code, and so you cannot bundle the Connection
and Statement
in the same structure. Instead, one can reference the other.
这篇关于如何在 Rust 的同一个结构中存储 rusqlite Connection 和 Statement 对象?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!