【发布时间】:2022-01-11 12:18:19
【问题描述】:
我在 rust 中遇到借用检查器和临时值问题。
我希望找到解决此特定问题的方法,并希望将来能更好地学习如何处理这种情况。我最初是从for_each 开始的,但遇到了提前终止的问题。
我考虑将check_foo 的逻辑移至update_foo,但这不适用于我的现实世界解决方案; MRE 侧重于编译问题与我在整个程序中试图实现的目标。
编辑:我有没有办法以纯功能的方式实现这一目标?
我想迭代一系列数字,更新 Vec<Foo> 并可能提前返回一个值。下面是我的代码具有相同错误的最小可重现示例:
我尝试尝试实现为:
fn run<'a>(mut foos: Vec<Foo>) -> Vec<&'a u32> {
let mut bar: Vec<&u32> = vec![];
for num in 0..10 {
for foo in &mut foos {
update_foo(foo);
let checked_foo = check_foo(&foo);
if checked_foo.is_empty() {
bar = checked_foo;
break;
}
}
}
bar
}
/* `fn update_foo` and `fn check_foo` definitions same as below */
但这导致:
21 | for foo in &mut foos {
| ^^^^^^^^^ `foos` was mutably borrowed here in the previous iteration of the loop
为了克服这个问题,我添加了 Rc 和 RefCell 的使用,以允许我在迭代引用的同时仍然能够变异:
#[derive(Clone, Debug, PartialEq)]
pub struct Foo {
updated: bool,
}
fn run<'a>(foos: Vec<Rc<RefCell<Foo>>>) -> Vec<&'a u32> {
let mut bar: Vec<&u32> = vec![];
for num in 0..10 {
for foo in &foos {
update_foo(&mut foo.borrow_mut());
let checked_foo = check_foo(&foo.borrow());
if checked_foo.is_empty() {
bar = checked_foo;
break;
}
}
}
bar
}
fn update_foo(foo: &mut Foo) {
foo.updated = true
}
fn check_foo(foo: &Foo) -> Vec<&u32> {
if foo.updated {
vec![&0, &1, &2]
} else {
vec![]
}
}
导致:
error[E0515]: cannot return value referencing temporary value
--> src/main.rs:33:5
|
26 | let checked_foo = check_foo(&foo.borrow());
| ------------ temporary value created here
...
33 | bar
| ^^^ returns a value referencing data owned by the current function
error[E0515]: cannot return value referencing function parameter `foos`
--> src/main.rs:33:5
|
23 | for foo in &foos {
| ----- `foos` is borrowed here
...
33 | bar
| ^^^ returns a value referencing data owned by the current function
For more information about this error, try `rustc --explain E0515`.
【问题讨论】:
-
在您陷入困境试图解决错误之前,您能否发布您拥有的原始简单代码?
-
嗨塞巴斯蒂安。我发布的是我的代码的 MRE。
check_foo的等价物内部有更多的逻辑,但除此之外并没有太大的不同。for foo in &mut foos是我在这个 fn 中的第一个错误,我在继续之前专注于解决。 -
好的,这里有一些问题。只有当您有一些可以拥有数据并且比对它的引用的寿命更长的结构时,才应该返回引用。否则,您需要确保您传递的数据是拥有的。我假设您不想将
foos的所有权转移到run函数,因为从那时起您将无法重用它。因此,这应该是一个参考。 -
任何时候你返回一些新数据,这些数据没有指向来自传入引用的数据,你应该拥有它,这样它就可以在函数返回后继续存在。需要注意的是
check_foo的签名扩展为fn check_foo(foo: &'a Foo) -> Vec<&'a u32>这不是你想要的。此签名意味着您将foo限制为比您返回的向量的元素寿命更长。 -
bar将是“引用当前函数拥有的数据”,因为借用检查器理解check_foo以返回对传入的foo的引用。因为Vec@987654342 @ 归函数所有,它会在返回之前被删除,Rust 认为您正在返回对已删除的结构的引用。
标签: rust borrow-checker