0

我刚刚开始学习 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 查询中获得一个结果的最佳方法,还是我完全错了?

4

1 回答 1

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)

于 2015-07-11T11:17:19.500 回答