返回引用的时间不够长

时间:2015-07-11 11:05:44

标签: mysql rust rust-cargo

我刚刚开始学习Rust,并且主要来自JavaScript背景,所以当谈到整个借用系统和内存管理时,我有点难过。

我有以下代码:

fn load(db: &MyPool, id: i32) -> &Account{
    let accounts: Vec<Account> = db.prepare("SELECT id, balance, name FROM `accounts` WHERE `id`=?")
    .and_then(|mut stmt| {
        stmt.execute(&[&id]).map(|result| {
            result.map(|x| x.unwrap()).map(|row| {
                Account{
                    id: from_value(&row[0]), 
                    balance: from_value(&row[1]), 
                    name: from_value(&row[2])
                }
            }).collect()
        })
    }).unwrap();

    &accounts[0]

}

我设法解决了编译器抛出的所有错误 /main.rs:42:4: 42:12 error: 'accounts' does not live long enough

这是从MySQL查询中获取一个结果的最佳方法,还是我完全错误了?

1 个答案:

答案 0 :(得分:2)

您不希望返回对帐户的引用,但是您希望在从数据库中检索后将所有权传递给调用者。

因此,将签名更改为:

fn load(db: &MyPool, id: i32) -> Account

现在的想法是按值返回对象,而不是通过引用:

accounts[0]

但是这样做会因error: cannot move out of indexed content而失败。更好的方法是避免完全收集向量,并使用Iterator::next(&self)来获取第一个元素。这看起来像是:

fn load(db: &MyPool, id: i32) -> Account{
    let account: Account = db.prepare("SELECT id, balance, name FROM `accounts` WHERE `id`=?")
    .and_then(|mut stmt| {
        stmt.execute(&[&id]).map(|result| {
            result.map(|x| x.unwrap()).map(|row| {
                Account{
                    id: from_value(&row[0]), 
                    balance: from_value(&row[1]), 
                    name: from_value(&row[2])
                }
            }).next().unwrap() // <- next() takes the first elt of the iterator
        })
    }).unwrap();

    account // <- return by value, pass ownership to caller
}

(未经测试,因为我无法重现您的开发环境。)

有点无关,但值得注意的是,那些多个unwrap()调用会使您的函数极其脆弱,因为任何失败都会使您的整个程序崩溃。幸运的是,这种难闻的气味的答案很简单:你想要返回Option<Account>而不是Account。然后移除对unwrap()的所有来电,并让Option<Account>在整个来电时传播(您使用map()是好的,因为如果您找到None,则会显示“返回None如果找到Some(f(a))“,请返回Some(a)。)