尽管 Rust 提供了 Rust 书籍,但我还是很难理解mut
关键字。我问自己:“我是唯一一个有这个问题的人吗?”谷歌的快速搜索证实我并不孤单。
因此,我决定写这篇文章来详细解释mut
关键字。本文适用于那些使用过 Python 或 JavaScript 等高级语言的人。
要在 Rust 中创建不可变变量,只需编写let x = 1337
。这很简单。如果你想创建一个可以稍后修改的变量,只需在let
后面添加mut
关键字即可。 Rust 有一个有用的约定,鼓励明确意图。
添加mut
关键字会通知其他人该变量将在代码中的其他位置进行修改。好的。
让我们想象一下。这里有两个变量, let mut x = 1337
和let y = 42
。
目前,一切都很简单。然而,当使用mut
引用时,事情开始变得有点复杂。让我们创建一些。
let mut x = 1337; let y = 42; let x_ref = &mut x; let y_ref = &y;
我创建了两个引用(或者用 Rust 的术语“借用”)。其中一个是可变引用,另一个是只读引用。让我们再次为此创建一个方案。
在给定的方案中,我有 4 个变量,其中 2 个是引用。两个引用变量都是不可变的,并且在let
之后没有mut
关键字,这意味着我无法更改它们指向的内容。但是,我仍然可以更改它们引用的值。
*x_ref = 777;
如果你这样写,Rust 编译器不会抱怨,并且x
的值(不是 ref 本身)将更改为777
。然而,该方案上有一个红色方块,表明x_ref
缺少可变性选项。那么,为什么我可以改变它所指的值呢?
让我们回到let x_ref = &mut x
的方案。
第一个白色块包含名称: x_ref
。第二个告诉我该变量中存储的类型。在其完整形式中,没有任何隐式类型注释,我可以编写如下:
let x_ref: &mut i32 = &mut x;
我可以将其解释为:让我们创建一个名为x_ref
的不可变变量,它将保存对i32
可变引用,并立即使用x
变量中对i32
值的可变引用对其进行初始化。
这意味着我可以修改它指向的值,但无法更改引用的值(或地址)。换句话说,我不能写这样的东西:
let x_ref: &mut i32 = &mut x; let mut z = 0; x_ref = &mut z; // Not allowed!
就方案而言,我想更改上面代码块中箭头指向的方向。但是,即使z
变量是可变的,我也无法更改箭头,因为问题在于x_ref
本身的不可变性。
要更改箭头方向,我需要修改x_ref
变量中存储的地址。但是,我不能这样做,因为变量是不可变的。
我们开始做吧!
let mut x: i32 = 1337; let mut x_ref: &mut i32 = &mut x; // I've added mut before x_ref let mut z = 0; x_ref = &mut z; // Allowed!
x_ref
周围有太多mut
实例,对吗?让我们来描述一下它们。
let mut x_ref
:我正在创建一个名为x_ref
的可变变量,这意味着我可以稍后更改它的值。
&mut i32
:我声明该变量将包含对i32
类型的某些值的可变引用。
&mut x
:我借用(引用)变量x
。
然后,我创建了一个名为z
的变量并为其指定了值0
。后来,当我写x_ref = &mut z
时,我表示我理解x_ref
是一个可变变量,只能保存对i32
值的引用。
由于z
的类型是i32
,我可以将其地址分配给x_ref
变量。为了获取z
的地址,我使用了&mut z
语法。
方案。
看看语句中的=
,可能看起来有点明显,但是……
let mut x_ref = &mut x;
…我将其视为一个分隔符(特别是如果将其旋转 90 度),将语句分为两个子语句:左和右。左侧提供有关变量本身的信息,而右侧则告诉我们有关值的信息。
当我使用*
取消引用运算符来更改值时...
*x_ref = 100;
...我不更改x_ref
变量的值。相反,我正在更改x_ref
引用的值。
我以前经常使用mut
。如果我省略其中一些怎么办?
let i = 1; let j = 2; let mut k = &i;
我可以改变这里的i
值吗?使用分隔符技术,回答起来非常简单。我可以更改k
的值(我在左侧看到mut
),但值(右侧)是对i
不可变引用(这里没有mut
)。
所以…
let i = 1; let j = 2; let mut k = &i; k = &j; // This is legal. *k = 3; // This is not.
方案。
在本文中,我们剖析了mut
关键字和引用的细微差别。请记住,可变引用和持有引用的可变变量之间是有区别的。我们的伎俩?
使用=
符号作为心理分隔符可以更好地理解 Rust 中的赋值。这个简单的可视化可以消除许多困惑。
快乐编码!