提问人:Rogus 提问时间:11/23/2022 最后编辑:Chayim FriedmanRogus 更新时间:11/23/2022 访问量:221
为什么 Rust 生命周期会破坏循环中的可变引用?
Why do Rust lifetimes break mutable references in loops?
问:
在尝试重构一个运行良好的 Rust 应用程序时,我试图将循环的内容分离到一个新函数中。但是,在这个新重构的函数中,我需要传递一个必须是可变的参数,并通过引用传递。突然间,绝对在内联中工作的代码仅仅因为可变引用传递而崩溃了。
我的问题是:有人可以解释为什么这不适用于如此“简单”的更改吗?(即重构原本未更改的代码的新函数)
我有一个关于这个问题的最小演示,以及下面的几个工作比较。这是该代码中的错误:
error[E0499]: cannot borrow `str_to_int` as mutable more than once at a time
--> src/main.rs:30:22
|
30 | get_key(key, &mut str_to_int);
| ^^^^^^^^^^^^^^^ `str_to_int` was mutably borrowed here in the previous iteration of the loop
示例代码:
use std::collections::BTreeMap;
fn get_int (
key: u32,
values: &mut BTreeMap<u32, u32>,
) -> &u32 {
values.entry(key).or_insert_with(|| { 1 })
}
fn get_key<'a> (
key: &'a str,
values: &'a mut BTreeMap<&'a str, u32>,
) -> &'a u32 {
values.entry(key).or_insert_with(|| { 1 })
}
fn main() {
let mut int_to_int = BTreeMap::new();
for key in vec![1,2] {
get_int(key, &mut int_to_int);
}
let mut str_to_int_inline = BTreeMap::new();
for key in vec!["a","b"] {
str_to_int_inline.entry(key).or_insert_with(|| { 1 });
}
let mut str_to_int = BTreeMap::new();
for key in vec!["a","b"] {
get_key(key, &mut str_to_int);
}
}
请注意,第一个循环 () 与第三个循环 () 相同,只是键的数据类型不同,因为键不是引用,因此不需要指定生存期。第二个循环 () 与第三个循环 () 相同,只是行为是内联的,而不是在单独的函数中。int_to_int
str_to_int
str_to_int_inline
str_to_int
关于这个话题有很多相关的问题和博客,但它们似乎都更具体地关注这个问题的特定版本,我想知道更通用的解释(根据我目前的理解)。如果答案已经只是为了更好地理解其中一个链接,我很乐意将这个问题标记为重复。
相关问题:
- 如何修复“..在 Rust 的上一次循环迭代中被可变地借用了“?
- https://users.rust-lang.org/t/mutable-borrow-starts-here-in-previous-iteration-of-loop/26145
- https://github.com/rust-lang/rust/issues/47680#issuecomment-363131420
- 为什么链接生存期只对可变引用有意义?
我读到的东西也让我想到了 https://github.com/rust-lang/polonius 这似乎也使它在未来能够发挥作用 - 有什么想法吗?
答:
您的问题很简单:您错误地指定了生存期。get_key()
正确(和工作)的版本是:
fn get_key<'a, 'b>(key: &'a str, values: &'b mut BTreeMap<&'a str, u32>) -> &'b u32 {
values.entry(key).or_insert_with(|| 1)
}
也许你已经猜到了发生了什么。
由于您同时使用了密钥本身及其密钥,这意味着您需要借用密钥的生命周期 - 。这意味着两件事:'a
HashMap
HashMap
'static
- 你需要一个 ,而你没有。
&'static mut HashMap
- 你在循环的第一次迭代中借用了 for,然后在下一次迭代中再次借用它,而它仍然被借用(因为它是借用的)。此错误隐藏了第一个错误,并且是编译器发出的唯一错误。
HashMap
'static
'static
通常,将生存期与可变引用一起使用两次几乎总是错误的(共享引用更宽容,因为它们的类型是协变的)。
评论
'a
key
value
key
vec!["a","b"]
main()
polonius-the-crab