在 Rust 中如何借用可变与不可变?

How borrow as mutable vs immutable in Rust?

我已阅读这些文档:https://doc.rust-lang.org/rust-by-example/scope/borrow/mut.html

我也看过这个问题:()


文档帮助我理解了如何将借用声明为可变的(我认为):

let mut (part1, part2) = someTuple;

但是我还没有找到关于什么是不可变借用的明确说明。这是我的猜测:

let (part1, part2) = someTuple;

我知道这是一个超级基本的问题,但谷歌搜索让我深入解释的深处,我仍在努力在最简单的上下文中找到方向。

我如何在 Rust 中作为可变借用与不可变借用?

let x = 0;
let immutable_borrow = &x; //borrow as immutable

//to borrow as mutable the variable needs to be declared as mutable
let mut y = 1;
let mutable_borrow = &mut y; //borrow as mutable

注意 1:您可以在同一范围内借用不可变或可变变量,这意味着您不能这样做:

let mut x = 0;
let immutable_borrow = &x;
let mutable_borrow = &mut x;

为什么?

因为如果您对同一个变量有可变和不可变引用,那么该变量的数据可能会通过该可变引用发生变化,这可能会导致很多问题。


注2:你可以不可变地借用一个变量无限次,但你只能可变地借用一个变量一次。

//You can do this
let x = 0;
let x1 = &x;
let x2 = &x;
//...

//But you can't do this
let mut y = 0;
let y1 = &mut y;
let y2 = &mut y; //won't compile if you use y1 after you declare y2

为什么?

如上所述。一个可变引用可能会更改所有其他可变引用所指向的数据,而它们并不知道。这可能会导致很多问题。但是拥有多个不可变引用是可以的,因为数据不会被意外更改。

Ejdrien 的回答演示了可变借用和不可变借用之间的区别,但是它没有解决您问题中的副标题,即您正在执行借用作为 pattern matching 的一部分。

写的时候

let (mut part1, mut part2) = someTuple;

您通过移动someTuple的内容绑定到可变变量part1part2。除非 someTuple 的内容 Copy 可用,否则变量 part1part2 将成为其各自值的唯一所有者。如果您稍后尝试通过写入访问 someTuple,例如

println!("{}", someTuple.0);

您将从借用检查器收到类似于

的编译错误
error[E0382]: borrow of moved value: `someTuple.0`
 --> main.rs:6:20
  |
4 |     let (mut part1, mut part2) = someTuple;
  |          --------- value moved here
5 | 
6 |     println!("{}", someTuple.0);
  |                    ^^^^^^^^^^^ value borrowed here after move

在这个特定的上下文中,有两种方法可以通知编译器我们只想借用 someTuple 的内容。第一种是 Ejdrien 描述的技术,它显式借用元组并针对结果引用执行模式匹配:

// Produce two mutable references
let (part1, part2) = &mut someTuple;

// Produce two immutable references
let (part1, part2) = &someTuple;

这种方法的问题是我们被迫以同样的方式借用一切。如果我们只想要对 someTuple.0 的可变引用,并希望将 someTuple.1 检索为副本或不可变引用怎么办?对于此处的元组示例,这似乎不是太关键,但对于更复杂的模式匹配情况,拥有这种类型的控制更为重要。

这给我们带来了第二种解决方案:绑定引用。代替上面的,我们可以写

// Produce two mutable references
let (ref mut part1, ref mut part2) = someTuple;

// Produce two immutable references
let (ref part1, ref part2) = someTuple;

在这里,我们明确说明我们希望如何在模式匹配中绑定每个变量。这里的关键是我们可以自由混合可变和不可变借用,因此以下内容也完全有效:

// Produce immutable reference and one mutable reference
let (ref part1, ref mut part2) = someTuple;

println!("{}", &someTuple.0); // Make a second immutable reference someTuple.0
*part2 = ... // Mutate someTuple.1
println!("{}", part1); // Continue using the immutable reference

如果我们将上面的内容与右侧的显式可变借用交换,由于同时存在可变和不可变引用,我们将再次从借用检查器收到错误:

let (part1, part2) = &mut someTuple;

println!("{}", &someTuple.0);
*part2 = ... // Mutate someTuple.1
println!("{}", part1);

产生

error[E0502]: cannot borrow `someTuple.0` as immutable because it is also borrowed as mutable
 --> main.rs:6:20
  |
4 |     let (part1,part2) =&mut someTuple;
  |                        -------------- mutable borrow occurs here
5 | 
6 |     println!("{}", &someTuple.0);
  |                    ^^^^^^^^^^^^ immutable borrow occurs here
...
9 |     println!("{}", part1);
  |                    ----- mutable borrow later used here

error: aborting due to previous error