Rust 数据库连接捆绑包的信任生存期

Rust 数据库连接捆绑包的信任生存期,rust,Rust,我试图设计一个结构来承载Postgres连接、事务和一组准备好的语句,然后重复执行准备好的语句。但我遇到了一生的问题。以下是我得到的: extern crate postgres; use postgres::{Connection, TlsMode}; use postgres::transaction::Transaction; use postgres::stmt::Statement; pub struct Db<'a> { conn: Connection,

我试图设计一个结构来承载Postgres连接、事务和一组准备好的语句,然后重复执行准备好的语句。但我遇到了一生的问题。以下是我得到的:

extern crate postgres;

use postgres::{Connection, TlsMode};
use postgres::transaction::Transaction;
use postgres::stmt::Statement;

pub struct Db<'a> {
    conn: Connection,
    tx: Transaction<'a>,
    insert_user: Statement<'a>,
}

fn make_db(url: &str) -> Db {
    let conn = Connection::connect(url, TlsMode::None).unwrap();
    let tx = conn.transaction().unwrap();
    let insert_user = tx.prepare("INSERT INTO users VALUES ($1)").unwrap();
    Db {
        conn: conn,
        tx: tx,
        insert_user: insert_user,
    }
}

pub fn main() {
    let db = make_db("postgres://paul@localhost/t");
    for u in &["foo", "bar"] {
        db.insert_user.execute(&[&u]);
    }
    db.tx.commit().unwrap();
}
我读过《铁锈书》(我记不清读了多少遍),但我不知道如何在这方面取得进展。有什么建议吗

编辑:再想一想,我仍然不明白为什么原则上我不能分辨锈迹,“
conn
的寿命和
Db
的寿命一样长”。问题在于移动
conn
,但如果我不移动它怎么办?我理解为什么在C语言中不能返回堆栈分配内存的指针,例如:

#包括
int*build_数组(){
int ar[]={1,2,3};
返回ar;
}
int main(){
int*ar=build_array();
printf(“%d\n”,ar[1]);
}
我明白了这和生锈或生锈是多么的相似

但在Rust中,您可以做到这一点:

但这会产生一个“意外的生命周期参数”错误。我可以接受Rust不能遵循逻辑,但我很好奇,是否有一个原则上不能遵循的原因

conn
放在堆上似乎可以解决我的问题,但我也无法让它工作:

pub struct Db<'a> {
    conn: Box<Connection>,
    tx: Transaction<'a>,
    insert_user: Statement<'a>,
}

但这仍然告诉我康恩活得不够长。似乎将其移动到结构中不需要任何真正的RAM更改,但Rust仍然不允许我这样做。

从这个函数开始:

fn make_db(url: &str) -> Db {
    unimplemented!()
}
由于,这相当于:

fn make_db<'a>(url: &'a str) -> Db<'a> {
    unimplemented!()
}

现在,这就更没有意义了,因为现在我们只是在拼凑一辈子。那
'b
来自哪里?如果
make_db
的调用方决定通用生存期参数
'b
的具体生存期应为
'static
,会发生什么情况?这在搜索“我们的创作功能确实有问题”中有进一步的解释

我们还看到问题中的“有时,我甚至没有参考价值”部分,答案中说:

子实例
包含对创建它的父实例的引用

如果我们查看以下内容:

fn事务结果
]没有什么意义。通常,当函数返回某个对象时,该对象只要被指定给某个对象就可以生存。为什么
->Db
不能以同样的方式工作

引用的全部要点是您不拥有引用的值。您返回
Db
,而
make_Db
的调用者将拥有它,但是谁拥有
Db
所指的东西?它是从哪里来的?您不能返回对本地内容的引用,因为这将违反Rust的所有安全规则。如果你想转让所有权,你就这么做

另见

使用,我整理了工作代码,使我能够将事务和所有准备好的语句捆绑起来,并将它们一起传递:

extern crate postgres;

use postgres::{Connection, TlsMode};
use postgres::transaction::Transaction;
use postgres::stmt::Statement;

pub struct Db<'a> {
    tx: Transaction<'a>,
    insert_user: Statement<'a>,
}

fn make_db(conn: &Connection) -> Db {
    let tx = conn.transaction().unwrap();
    let insert_user = tx.prepare("INSERT INTO users VALUES ($1)").unwrap();
    Db {
        tx: tx,
        insert_user: insert_user,
    }
}

pub fn main() {
    let conn = Connection::connect("postgres://paul@localhost/t", TlsMode::None).unwrap();
    let db = make_db(&conn);
    for u in &["foo", "bar"] {
        db.insert_user.execute(&[&u]);
    }
    db.tx.commit().unwrap();
}
extern板条箱postgres;
使用postgres::{Connection,TlsMode};
使用postgres::transaction::transaction;
使用postgres::stmt::语句;
发布结构数据库,

insert_user:StatementSee与您的问题非常接近,该问题被标记为的重复问题。我发现该问题实际上没有可用代码的答案。还有您链接到的另一个问题:我没有在结构中使用任何引用。请确保您彻底阅读了重复的问题。具体地说,你刚才说的道德等同于“有时,我甚至没有引用值,我从副本中得到相同的错误”。提示:这就是那些
'a
生命周期的意思-一个参考。这条评论的最后一行是我每次遇到StackOverflow生锈问题时的亲身经历:从你的链接答案中,我看到当生锈文档说“移动”时,他们的意思不仅是“移动到新的所有者”,而且是“移动到RAM中的一个新地方”。这对我来说是一条非常有用的新信息。“现在这更没有意义了,因为现在我们只是在弥补生命。”---我不明白为什么它没有意义。通常,当函数返回某个对象时,该对象只要被指定给某个对象就可以生存。为什么
->Db
不能以同样的方式工作?是的,“生存期”可能更恰当地表述为“保证值的地址不改变的程序范围”,但没有人会这么说。好的,我真的很感谢您的耐心和帮助。我自己写了一个答案,显示工作代码接近我想要的。还有一些概念我还不明白,但我正在研究。特别是:由于我的结构没有引用,难道不是所有的东西都“移动”到它里面,它就成为了这些东西的所有者吗?但我确实理解
conn
怎么永远不能移动,因为
tx
有一个引用。@PaulAJungwirth您的结构中100%有引用,它们恰好在另一个结构中。请参见上述
事务的定义
——它包含一个参考。因此,包含
事务的结构具有引用。
fn make_db(url: &str) -> Db {
    unimplemented!()
}
fn make_db<'a>(url: &'a str) -> Db<'a> {
    unimplemented!()
}
fn make_db<'a, 'b>(url: &'a str) -> Db<'b> {
    unimplemented!()
}
fn transaction<'a>(&'a self) -> Result<Transaction<'a>>
pub struct Transaction<'conn> {
    conn: &'conn Connection,
    depth: u32,
    savepoint_name: Option<String>,
    commit: Cell<bool>,
    finished: bool,
}
extern crate postgres;

use postgres::{Connection, TlsMode};
use postgres::transaction::Transaction;
use postgres::stmt::Statement;

pub struct Db<'a> {
    tx: Transaction<'a>,
    insert_user: Statement<'a>,
}

fn make_db(conn: &Connection) -> Db {
    let tx = conn.transaction().unwrap();
    let insert_user = tx.prepare("INSERT INTO users VALUES ($1)").unwrap();
    Db {
        tx: tx,
        insert_user: insert_user,
    }
}

pub fn main() {
    let conn = Connection::connect("postgres://paul@localhost/t", TlsMode::None).unwrap();
    let db = make_db(&conn);
    for u in &["foo", "bar"] {
        db.insert_user.execute(&[&u]);
    }
    db.tx.commit().unwrap();
}