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