在多个闭包中表达变量对的生命周期
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();
})
}
代码存在多个问题:
conn
活得不够长。它也需要移动到闭包。可能因为两次闭包而成为 Rc<Connection>
?
由于可变性要求,conn
不能简单地共享为 Rc
。也许 Rc<RefCell<Connection>>
是更合适的类型?
- 借用检查器不知道对
tx
的借用在第一个 for_each
闭包后结束,因此不能移动到第二个 map
闭包。再一次,将它作为 Rc<Transaction>
移动到两个闭包可能是合理的?
我一直在摆弄这些想法,并且知道所需的生命周期是可能的并且有意义,但无法以正确的方式向编译器表达我的代码。
我相信你的第一个问题是你还没有完全理解 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?
我正在努力以取悦借用检查员的方式表达我的代码。
我有一个函数 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();
})
}
代码存在多个问题:
conn
活得不够长。它也需要移动到闭包。可能因为两次闭包而成为Rc<Connection>
?
由于可变性要求,conn
不能简单地共享为Rc
。也许Rc<RefCell<Connection>>
是更合适的类型?- 借用检查器不知道对
tx
的借用在第一个for_each
闭包后结束,因此不能移动到第二个map
闭包。再一次,将它作为Rc<Transaction>
移动到两个闭包可能是合理的?
我一直在摆弄这些想法,并且知道所需的生命周期是可能的并且有意义,但无法以正确的方式向编译器表达我的代码。
我相信你的第一个问题是你还没有完全理解 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?