循环中的多个可变引用
Multiple mutable references in a loop
我正在尝试更详细地了解 Rust 的所有权和生命周期,但我对这段代码感到很困惑:
let mut lst = vec![1, 2, 3];
let mut x = &mut 0;
for value in &mut lst {
*value += 1;
*x += 1;
x = value;
}
*x += 1;
println!("{:?}", &lst);
据我了解,Rust 不允许对任何值有多个可变引用,并且对向量中元素的可变引用也会借用向量本身。因此,不可能同时对向量中的两个元素进行可变引用。
但是在上面的代码中,循环体在循环外的x
中存储了对lst
中元素的可变引用。然后,在下一次迭代中,它需要 another 对 lst
中不同元素的可变引用,给我 two 对两个元素的可变引用列表中的元素。
所以我的问题是:为什么允许这样做?
最后你只持有一个 mut 引用,在 x = value
中引用被移动到 x
中。如果该行在循环中是第一行,情况会有所不同:
fn main() {
let mut lst = vec![1, 2, 3];
let mut x = &mut 0;
for value in &mut lst {
x = value;
*value += 1;
*x += 1;
}
*x += 1;
println!("{:?}", &lst);
}
编译器当然会抱怨的地方:
error[E0503]: cannot use `*value` because it was mutably borrowed
--> src/main.rs:8:9
|
6 | x = value;
| ----- borrow of `*value` occurs here
7 |
8 | *value += 1;
| ^^^^^^^^^^^ use of borrowed `*value`
9 | *x += 1;
| ------- borrow later used here
虽然 Rust 不允许您对同一值有多个可变引用,但它确实允许您对同一值的非重叠部分有可变引用。
例如,您可以将 &mut T
拆分为每个字段的单独可变引用,借用检查器将为您跟踪:
struct Foo {
x: i32,
y: i32,
}
let mut foo = Foo { x: 0, y : 0 };
let foo_mut = &mut foo;
let x = &mut foo_mut.x;
let y = &mut foo_mut.y;
*x = 1;
*y = 2;
println!("x = {:?}", x); // 1
println!("y = {:?}", y); // 2
println!("foo = {:?}", foo); // Foo { x: 1, y: 2 }
同样,您可以使用 split_at_mut
and split_first_mut
等方法拆分可变切片引用 &mut [T]
,这两种方法都会为您提供两个不重叠的切片引用。
实际上,可以使用split_first_mut
:
实现可变切片的迭代
let mut lst = vec![1, 2, 3];
let mut x = &mut 0;
let mut rest = &mut *lst;
while let Some((value, rest_)) = rest.split_first_mut() {
rest = rest_;
*value += 1;
*x += 1;
x = value;
}
*x += 1;
println!("{:?}", &lst);
所以&mut [T]
(和&mut Vec<T>
)的迭代器可以提供多个共存的可变引用,只要这些可变引用指向向量的不同部分并且不重叠.
我正在尝试更详细地了解 Rust 的所有权和生命周期,但我对这段代码感到很困惑:
let mut lst = vec![1, 2, 3];
let mut x = &mut 0;
for value in &mut lst {
*value += 1;
*x += 1;
x = value;
}
*x += 1;
println!("{:?}", &lst);
据我了解,Rust 不允许对任何值有多个可变引用,并且对向量中元素的可变引用也会借用向量本身。因此,不可能同时对向量中的两个元素进行可变引用。
但是在上面的代码中,循环体在循环外的x
中存储了对lst
中元素的可变引用。然后,在下一次迭代中,它需要 another 对 lst
中不同元素的可变引用,给我 two 对两个元素的可变引用列表中的元素。
所以我的问题是:为什么允许这样做?
最后你只持有一个 mut 引用,在 x = value
中引用被移动到 x
中。如果该行在循环中是第一行,情况会有所不同:
fn main() {
let mut lst = vec![1, 2, 3];
let mut x = &mut 0;
for value in &mut lst {
x = value;
*value += 1;
*x += 1;
}
*x += 1;
println!("{:?}", &lst);
}
编译器当然会抱怨的地方:
error[E0503]: cannot use `*value` because it was mutably borrowed
--> src/main.rs:8:9
|
6 | x = value;
| ----- borrow of `*value` occurs here
7 |
8 | *value += 1;
| ^^^^^^^^^^^ use of borrowed `*value`
9 | *x += 1;
| ------- borrow later used here
虽然 Rust 不允许您对同一值有多个可变引用,但它确实允许您对同一值的非重叠部分有可变引用。
例如,您可以将 &mut T
拆分为每个字段的单独可变引用,借用检查器将为您跟踪:
struct Foo {
x: i32,
y: i32,
}
let mut foo = Foo { x: 0, y : 0 };
let foo_mut = &mut foo;
let x = &mut foo_mut.x;
let y = &mut foo_mut.y;
*x = 1;
*y = 2;
println!("x = {:?}", x); // 1
println!("y = {:?}", y); // 2
println!("foo = {:?}", foo); // Foo { x: 1, y: 2 }
同样,您可以使用 split_at_mut
and split_first_mut
等方法拆分可变切片引用 &mut [T]
,这两种方法都会为您提供两个不重叠的切片引用。
实际上,可以使用split_first_mut
:
let mut lst = vec![1, 2, 3];
let mut x = &mut 0;
let mut rest = &mut *lst;
while let Some((value, rest_)) = rest.split_first_mut() {
rest = rest_;
*value += 1;
*x += 1;
x = value;
}
*x += 1;
println!("{:?}", &lst);
所以&mut [T]
(和&mut Vec<T>
)的迭代器可以提供多个共存的可变引用,只要这些可变引用指向向量的不同部分并且不重叠.