返回引用的寿命不够长
Returning a reference does not live long enough
我刚开始学习 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 查询中获得一个结果的最佳方式,还是我一直在做完全错误的事情?
您不想return一个帐户的引用,但您希望在从数据库中检索后将所有权传递给调用者。
因此,将签名更改为:
fn load(db: &MyPool, id: i32) -> Account
现在的想法是 return 按值而不是引用对象:
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()
调用会使您的函数变得非常脆弱,因为任何失败都会使您的整个程序崩溃并引起恐慌。幸运的是,解决这种难闻气味的方法很简单:你想要 return Option<Account>
而不是 Account
。然后删除对 unwrap()
的所有调用并让 Option<Account>
在整个调用中传播(您对 map()
的使用很好,因为它表示 "return None
if you find None
and return Some(f(a))
if you find Some(a)
"。)
我刚开始学习 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 查询中获得一个结果的最佳方式,还是我一直在做完全错误的事情?
您不想return一个帐户的引用,但您希望在从数据库中检索后将所有权传递给调用者。
因此,将签名更改为:
fn load(db: &MyPool, id: i32) -> Account
现在的想法是 return 按值而不是引用对象:
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()
调用会使您的函数变得非常脆弱,因为任何失败都会使您的整个程序崩溃并引起恐慌。幸运的是,解决这种难闻气味的方法很简单:你想要 return Option<Account>
而不是 Account
。然后删除对 unwrap()
的所有调用并让 Option<Account>
在整个调用中传播(您对 map()
的使用很好,因为它表示 "return None
if you find None
and return Some(f(a))
if you find Some(a)
"。)