借用编译的SQL语句的问题

nja*_*ard 5 rust borrow-checker

我的程序使用rusqlite从另一个数据源构建数据库.数据库以相同的方式构建多个表,所以我想我会创建一个可重用的函数:

fn download_generic<Inserter>(table_name: &str,
                              connection: &mut rusqlite::Connection,
                              inserter: &mut Inserter)
                              -> Result<(), String>
    where Inserter: FnMut(&str, &json::JsonValue) -> ()
{}
Run Code Online (Sandbox Code Playgroud)

inserter 是一个函数,它绑定先前准备的语句中的正确值并进行插入.

我称之为:

let mut insert_stmt = connection
    .prepare("insert or replace into categories values(?,?);")
    .unwrap();

download_generic("categories",
                 &mut connection,
                 &mut |uuid, jsonproperties| {
                     insert_stmt.execute(&[&uuid, &jsonproperties["name"].as_str().unwrap_or("")]);
                 });
Run Code Online (Sandbox Code Playgroud)

但是我无法传递&mut connection,download_generic因为它已经被借来了insert_stmt.将它放入一个RefCell没有意义,因为我不需要运行时开销来使这项工作.

我可以尝试insert_stmt通过你传递给它的lambda来生成download_generic,但是后来我不得不在任何地方添加生命周期标记而感到不知所措,无论如何它似乎都不自然.

Fra*_*gné 2

按照设计,Rust 会阻止您同时对同一对象进行不可变借用和可变借用。这是为了防止悬空指针和数据争用。

在 rusqlite 的 API 中,有些方法Connection需要 mutable self,有些方法只需要 immutable self。然而,一些方法只需要一个不可变的self返回对象来保持借用活动;prepare就是一个例子。因此,只要这些对象之一保留在范围内,Rust 就不允许您在Connection.

某些方法采用可变引用可能是有原因的self。要求可变引用可确保被调用者具有对该对象的独占访问权限。如果您认为您需要使用的方法可能不是这种情况,或者您认为可能有另一种方法来解决此问题,那么您应该向库的维护人员报告问题。

具体来说,您可以通过从闭包内部prepare调用来解决冲突的借用问题。prepare_cached为了做到这一点,你必须将back 作为参数download_generic传递connection给闭包,否则你将有两个可变借用connection,这是不允许的。