我正在处理我的第一个Rust程序,并且与Rust所有权语义相冲突。我声明了一个struct
,它将封装一个SQLite数据库连接,因此它维护一个Connection
成员。出于性能原因,我还想保留一份由Statement
类型表示的预准备语句。这是我的代码的简化版本:
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
的成员来将其转移给被调用者,但是当我尝试编译此代码时,它失败了:
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
实例的生命周期联系起来。
我错过了什么?这种封装是一种非常常见的模式,我确定我错过了一些东西。
答案 0 :(得分:8)
让我们看一下Connection::prepare
:
pub fn prepare<'a>(&'a self, sql: &str) -> Result<Statement<'a>>
如果我们忽略Result
(这只意味着此功能可能失败),这意味着&#34;返回Statement
不能超过Connection
prepare
的{{1}} {1}}被调用了#34;。这可能是由于Statement
包含对Connection
的引用。
但是,如果您对某个项目有引用,则无法再移动该项目,因为该引用将失效。使用该无效引用会导致内存不安全,因此无法使用。
基本上,您需要在代码中镜像这些对象的生命周期和所有权,因此您无法将Connection
和Statement
捆绑在同一个结构中。相反,人们可以引用另一个。