我正在开发我的第一个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实例的生存期联系起来.

我错过了什么?这种封装是一种非常常见的模式,我确信我遗漏了一些东西.

推荐答案

让我们看看Connection::prepare:

pub fn prepare<'a>(&'a self, sql: &str) -> Result<Statement<'a>>

如果我们忽略Result(这仅仅意味着这个函数可能会失败),这意味着"返回一个Statement,它的生命周期 不能超过prepare被调用的Connection".这可能是因为Statement包含对Connection的引用.

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

基本上,您需要在代码中镜像这些对象的生命周期和所有权,因此不能将ConnectionStatementBundle 在同一个 struct 中.相反,一方可以引用另一方.

Rust相关问答推荐

如何在rust中有条件地分配变量?

阻止websocket中断的中断中断的终端(操作系统错误4)

将JSON密钥转换为Polars DataFrame

使用 struct 外部的属性来改变 struct 的原始方式

在Rust中,如果Result是Err,运行副作用(如日志(log)记录)的惯用方法是什么

原始数组数据类型的默认trait实现

在Rust中是否可以使用Rc自动化约束传播

如何高效地将 struct 向量中的字段收集到单独的数组中

如何在 Rust 中编写一个通用方法,它可以接受任何可以转换为另一个值的值?

为什么 Rust 需要可变引用的显式生命周期而不是常规引用?

Rust 重写函数参数

为什么Rust中无法推断生命周期?

`tokio::pin` 如何改变变量的类型?

push 方法是否取得所有权?

为什么 i32 Box 类型可以在 Rust 中向下转换?

LinkedList::drain_filter::drop 中 DropGuard 的作用是什么?

Iterator::collect如何进行转换?

需要括号的宏调用中的不必要的括号警告 - 这是编写宏的糟糕方法吗?

为什么这里需要类型注解?

在 macro_rules 中转义 $ 美元符号