在多个闭包中表达变量对的生命周期

Expressing lifetimes of a variable pair within multiple closures

我正在努力以取悦借用检查员的方式表达我的代码。

我有一个函数 create_task 可以创建一些数据库操作的未来。有一个值流,其中每个元素都需要插入到事务中的数据库中。问题是在多个闭包之间共享事务,因为它也可变地借用了连接对象。

#![feature(conservative_impl_trait)]

extern crate futures;
extern crate rusqlite;

use futures::prelude::*;
use futures::{future, stream};
use rusqlite::Connection;

fn main() {
    let task = create_task();
    task.wait().unwrap();
}

fn create_task() -> impl Future<Item = (), Error = ()> {
    let mut conn = Connection::open("temp.db").unwrap();
    conn.execute("CREATE TABLE IF NOT EXISTS temp (val INTEGER)", &[]).unwrap();

    // tx takes a mut ref to conn!
    let tx = conn.transaction().unwrap();

    stream::iter_ok::<_, ()>(vec![1, 2, 3])
        .for_each(|val| {
            // tx borrowed here!
            tx.execute("INSERT INTO temp (val) VALUES (?1)", &[&val]).unwrap();
            future::ok(())
        })
        .map(|_| {
            // tx moved/consumed here!
            tx.commit().unwrap();
        })
}

代码存在多个问题:

我一直在摆弄这些想法,并且知道所需的生命周期是可能的并且有意义,但无法以正确的方式向编译器表达我的代码。

我相信你的第一个问题是你还没有完全理解 futures 有多么懒惰。您正在 create_task 中创建一个 Connection,引用它,将该引用放入 stream/future,然后尝试 return 那个未来。 None 个闭包甚至在此时执行.

cannot return a reference to a value created in a function. Don't try to .

相反,接受对 Connection 和 return 包含该生命周期的 Future 的引用。

下一个问题是编译器不知道如何调用闭包或以什么顺序调用。不要试图关闭交易,而是让它 "flow" 从一个到另一个,让所有权系统确保它总是在正确的地方。

#![feature(conservative_impl_trait)]

extern crate futures;
extern crate rusqlite;

use futures::prelude::*;
use futures::{future, stream};
use rusqlite::Connection;

fn main() {
    let mut conn = Connection::open("temp.db").unwrap();
    conn.execute("CREATE TABLE IF NOT EXISTS temp (val INTEGER)", &[]).unwrap();

    let task = create_task(&mut conn);
    task.wait().unwrap();
}

fn create_task<'a>(conn: &'a mut rusqlite::Connection) -> impl Future<Item = (), Error = ()> + 'a {
    let tx = conn.transaction().unwrap();
    stream::iter_ok::<_, ()>(vec![1, 2, 3])
        .fold(tx, |tx, val| {
            tx.execute("INSERT INTO temp (val) VALUES (?1)", &[&val]).unwrap();
            future::ok(tx)
        })
        .map(move |tx| {
            tx.commit().unwrap();
        })
}

一个巨大的警告:如果 execute 不是异步的,你 真的 不应该在这样的未来中使用它。任何阻塞操作都会导致你所有的期货停滞不前。您可能应该 运行 单独线程/线程池上的同步工作负载。

另请参阅:

  • Is there any way to return a reference to a variable created in a function?