【发布时间】:2022-01-10 15:40:07
【问题描述】:
我时不时地在循环中借用(或不借用)可变变量时遇到同样的问题,最后我坐下来编译了一个最小的示例。结果,代码有点傻,但它是我能想到的最短的版本,突出了问题:
struct Association {
used: bool,
key: usize,
value: String,
}
impl Association {
fn new(key: usize, value: &str) -> Self {
Association{used: false, key: key, value: value.to_string()}
}
}
fn find_unused<'a>(data: &'a mut Vec<Association>) -> Option<&'a String> {
for k in 0.. {
for a in data {
if a.key == k && !a.used {
a.used = true;
return Some(&a.value);
}
}
}
None
}
fn main() {
let mut assoc = vec![
Association::new(7, "Hello"),
Association::new(9, "World")
];
println!("{}", find_unused(&mut assoc).unwrap());
println!("{}", find_unused(&mut assoc).unwrap());
}
这将失败并出现错误,因为 data 之前已移动。如果我改为借它,它会失败,因为它是以前借的。我想准确了解正在发生的事情以及如何解决它。特别是,我不想改变代码的结构,即使它很傻。我不想实现一个解决方法,因为这只是一个最小的例子:请假设循环的嵌套是“正确”的方法,即使它在这里完全愚蠢,它肯定是。
我只想知道如何与借阅检查器沟通这里发生的事情实际上是可以的。我知道一种方法可以做到这一点:
fn find_unused<'a>(data: &'a mut Vec<Association>) -> Option<&'a String> {
for k in 0.. {
for j in 0..data.len() {
if data[j].key == k && !data[j].used {
data[j].used = true;
return Some(&data[j].value);
}
}
}
None
}
这编译没有错误并按预期工作。以我的幼稚理解,应该有一种方法可以用迭代器而不是索引来表达上述内容,我想知道如何做到这一点。
【问题讨论】:
-
更好的代码play.integer32.com/…
-
亲爱的@Stargateur,请注意我的免责声明并假设代码重组不是解决方案,即使它绝对适用于minimal示例。了解这实际上不是我正在编写的代码,并且以这种方式重组并不总是可行的。我确实在夜间频道上启用了非词汇生命周期支持,但至少我不能让它在启用该功能的情况下工作。
-
您已经在使用 NLL,请阅读两次 shepmaster 的答案,这是当前 NLL 实现的当前限制。试试
-Zpolonius。在我给出的解决方案上,它只是为了帮助您有一种使用迭代器的方法,如果您没有创建一个真正展示您的用例的minimal reproducible example,您就不能抱怨。我不是魔术师。 -
@JeskoHüttenhain 我不确定是否可以发布答案,但我最近遇到了类似的情况并偶然发现:github.com/rust-lang/rust/issues/51526 与我的代码非常匹配。似乎有条件地从循环中返回借用是特别的问题,它不知道结束循环的借用。 (而且我猜索引版本是有效的,因为没有借用数据。)但是,最终我对 NLL 的了解还不足以肯定地说。
标签: rust iterator borrow-checker mutability