如何在 Rust 的同一个结构中存储 rusqlite Connection 和 Statement 对象? [英] How to store rusqlite Connection and Statement objects in the same struct in Rust?

查看:31
本文介绍了如何在 Rust 的同一个结构中存储 rusqlite Connection 和 Statement 对象?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在开发我的第一个 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.

基本上,您需要在代码中反映这些对象的生命周期和所有权,因此您不能将 ConnectionStatement 捆绑在同一结构中.相反,一个可以引用另一个.

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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆