如何在Rust的同一个结构中存储rusqlite Connection和Statement对象?

ane*_*son 8 rust

我正在研究我的第一个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 }
    }
}
Run Code Online (Sandbox Code Playgroud)

我试图通过将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> {
   |      ^^
Run Code Online (Sandbox Code Playgroud)

由于某种原因,该rusqlite::Connection类型不会使用生命周期参数,因此我无法将其生命周期与Statement实例的生命周期明确联系起来.

我错过了什么?这种封装是一种非常常见的模式,我敢肯定我错过了一些东西.

She*_*ter 8

我们来看看Connection::prepare:

pub fn prepare<'a>(&'a self, sql: &str) -> Result<Statement<'a>>
Run Code Online (Sandbox Code Playgroud)

如果我们忽略了Result(这只是意味着该功能可能会失败),这意味着"返回一个Statement能活的时间不会比Connection那个prepare叫上".这可能是由于Statement包含了对该引用的引用Connection.

但是,如果您有对项目的引用,则您无法再移动该项目,因为该引用将失效.使用该无效引用会导致内存不安全,因此无法使用.

基本上,你需要以反映这些对象的生命周期和所有权在你的代码,所以你不能捆绑Connection,并Statement在相同的结构.相反,人们可以引用另一个.

  • 在实际代码中,sql连接+ 2个预处理语句会是什么样子? (3认同)