为什么可变借用的顺序在 Rust 中很重要?
Why does order of mutable borrows matter in Rust?
此代码编译 (playground link):
use std::collections::HashMap;
fn main() {
let mut h = HashMap::<char, Vec<i32>>::new();
h.insert('a', vec![0]);
let first_borrow = h.get_mut(&'a').unwrap();
first_borrow.push(1);
let second_borrow = h.get_mut(&'a').unwrap();
second_borrow.push(2);
}
正在使用借用更改代码顺序(push()
调用)...
let first_borrow = h.get_mut(&'a').unwrap();
let second_borrow = h.get_mut(&'a').unwrap();
first_borrow.push(1);
second_borrow.push(2);
...使其无法编译:
error[E0499]: cannot borrow `h` as mutable more than once at a time
--> src/main.rs:8:25
|
7 | let first_borrow = h.get_mut(&'a').unwrap();
| - first mutable borrow occurs here
8 | let second_borrow = h.get_mut(&'a').unwrap();
| ^ second mutable borrow occurs here
9 | first_borrow.push(1);
| ------------ first borrow later used here
此外,在 second_borrow
的实例化之后使用 first_borrow
也无法编译:
let first_borrow = h.get_mut(&'a').unwrap();
first_borrow.push(1);
let second_borrow = h.get_mut(&'a').unwrap();
second_borrow.push(2);
// ...
first_borrow.push(1);
考虑到文档中关于作用域的内容,这令人惊讶。在编译的代码中,为什么我们不在那里也有两个可变借用?
在编译的例子中,Rust 是否看到,在 let second_borrow = ...
之后,任何地方都不再提到 first_borrow
,所以它 unborrows 可变的借用 first_borrow
并因此在 main()
?!
的整个范围内保留一次借用
在编译的代码中,为什么我们不在那里也有两个可变借用?
简短的回答是同一块数据的两个可变借用不能同时在范围内,第一个示例没有违反该限制。请注意,这是可变引用的“一大限制”的必然结果,即“您只能对特定范围内的特定数据片段使用一个可变引用”。请参阅 Rust 编程语言中的 References and Borrowing 部分。
您的第一个示例编译是因为 first_borrow
在 second_borrow
进入范围之前超出了范围。 “超出范围”与未在范围的其余部分引用的变量同义。我不知道底层细节,但这是我对这个例子的看法。
// first_borrow comes into scope
let first_borrow = h.get_mut(&'a').unwrap();
first_borrow.push(1);
// first_borrow goes out of scope
// second_borrow comes into scope
let second_borrow = h.get_mut(&'a').unwrap();
second_borrow.push(2);
// second_borrow goes out of scope
对于您的第二个未编译的示例,我们可以看到 first_borrow
和 second_borrow
的范围交叉。
// first_borrow comes into scope
let first_borrow = h.get_mut(&'a').unwrap();
// second_borrow comes into scope
let second_borrow = h.get_mut(&'a').unwrap();
// !!! both first_borrow and second_borrow are in scope now !!!
first_borrow.push(1);
// first_borrow goes out of scope
second_borrow.push(2);
// second_borrow goes out of scope
在编译的例子中,Rust 是否看到,在 let second_borrow = ... 之后,任何地方都不再提及 first_borrow,所以它取消了 [=36 的可变借用=] 从而在 main() 的整个范围内保留一次借用?!
有效,是的。不过,我不认为这是不借钱的。如上所述,我认为该术语是 first_borrow
超出范围。
例如,您可以这样编写第一个示例。
{
let first_borrow = h.get_mut(&'a').unwrap();
first_borrow.push(1);
}
{
let second_borrow = h.get_mut(&'a').unwrap();
second_borrow.push(2);
}
当然第二个例子不能这样写,因为借位相互交叉
此代码编译 (playground link):
use std::collections::HashMap;
fn main() {
let mut h = HashMap::<char, Vec<i32>>::new();
h.insert('a', vec![0]);
let first_borrow = h.get_mut(&'a').unwrap();
first_borrow.push(1);
let second_borrow = h.get_mut(&'a').unwrap();
second_borrow.push(2);
}
正在使用借用更改代码顺序(push()
调用)...
let first_borrow = h.get_mut(&'a').unwrap();
let second_borrow = h.get_mut(&'a').unwrap();
first_borrow.push(1);
second_borrow.push(2);
...使其无法编译:
error[E0499]: cannot borrow `h` as mutable more than once at a time
--> src/main.rs:8:25
|
7 | let first_borrow = h.get_mut(&'a').unwrap();
| - first mutable borrow occurs here
8 | let second_borrow = h.get_mut(&'a').unwrap();
| ^ second mutable borrow occurs here
9 | first_borrow.push(1);
| ------------ first borrow later used here
此外,在 second_borrow
的实例化之后使用 first_borrow
也无法编译:
let first_borrow = h.get_mut(&'a').unwrap();
first_borrow.push(1);
let second_borrow = h.get_mut(&'a').unwrap();
second_borrow.push(2);
// ...
first_borrow.push(1);
考虑到文档中关于作用域的内容,这令人惊讶。在编译的代码中,为什么我们不在那里也有两个可变借用?
在编译的例子中,Rust 是否看到,在 let second_borrow = ...
之后,任何地方都不再提到 first_borrow
,所以它 unborrows 可变的借用 first_borrow
并因此在 main()
?!
在编译的代码中,为什么我们不在那里也有两个可变借用?
简短的回答是同一块数据的两个可变借用不能同时在范围内,第一个示例没有违反该限制。请注意,这是可变引用的“一大限制”的必然结果,即“您只能对特定范围内的特定数据片段使用一个可变引用”。请参阅 Rust 编程语言中的 References and Borrowing 部分。
您的第一个示例编译是因为 first_borrow
在 second_borrow
进入范围之前超出了范围。 “超出范围”与未在范围的其余部分引用的变量同义。我不知道底层细节,但这是我对这个例子的看法。
// first_borrow comes into scope
let first_borrow = h.get_mut(&'a').unwrap();
first_borrow.push(1);
// first_borrow goes out of scope
// second_borrow comes into scope
let second_borrow = h.get_mut(&'a').unwrap();
second_borrow.push(2);
// second_borrow goes out of scope
对于您的第二个未编译的示例,我们可以看到 first_borrow
和 second_borrow
的范围交叉。
// first_borrow comes into scope
let first_borrow = h.get_mut(&'a').unwrap();
// second_borrow comes into scope
let second_borrow = h.get_mut(&'a').unwrap();
// !!! both first_borrow and second_borrow are in scope now !!!
first_borrow.push(1);
// first_borrow goes out of scope
second_borrow.push(2);
// second_borrow goes out of scope
在编译的例子中,Rust 是否看到,在 let second_borrow = ... 之后,任何地方都不再提及 first_borrow,所以它取消了 [=36 的可变借用=] 从而在 main() 的整个范围内保留一次借用?!
有效,是的。不过,我不认为这是不借钱的。如上所述,我认为该术语是 first_borrow
超出范围。
例如,您可以这样编写第一个示例。
{
let first_borrow = h.get_mut(&'a').unwrap();
first_borrow.push(1);
}
{
let second_borrow = h.get_mut(&'a').unwrap();
second_borrow.push(2);
}
当然第二个例子不能这样写,因为借位相互交叉