Rust は Rust ブックを提供していますが、私はmut
キーワードを理解するのに苦労しました。 「この問題を抱えているのは私だけでしょうか?」と自問しました。 Google で簡単に検索したところ、私が一人ではないことがわかりました。
その結果、 mut
キーワードについて詳しく説明するためにこの記事を書くことにしました。この記事は、Python や JavaScript などの高級言語を使用するユーザーを対象としています。
Rustで変更不可能な変数を作成するには、単にlet x = 1337
と書くだけです。それは簡単です。後で変更できる変数を作成したい場合は、 let
の後にmut
キーワードを追加するだけです。 Rust には、意図を明確にするための便利な規約があります。
mut
キーワードを追加すると、この変数がコード内の別の場所で変更されることが他の人に通知されます。わかった。
それを視覚化してみましょう。ここでは 2 つの変数、 let mut x = 1337
およびlet y = 42
。
現時点では、すべてが簡単です。ただし、 mut
参照を使用すると、状況が少し複雑になり始めます。いくつか作成してみましょう。
let mut x = 1337; let y = 42; let x_ref = &mut x; let y_ref = &y;
2 つのリファレンスを作成しました (Rust の用語で「借用」)。それらの 1 つは変更可能な参照であり、もう 1 つは読み取り専用の参照です。そのためのスキームをもう一度作成しましょう。
指定されたスキームには 4 つの変数があり、そのうち 2 つは参照です。どちらの参照変数も不変で、 let
の後にmut
キーワードがありません。つまり、それらが指すものを変更することはできません。ただし、参照される値は変更できます。
*x_ref = 777;
これを書くと、Rust コンパイラは文句を言わず、 x
の値 (ref 自体ではない) が777
に変更されます。ただし、スキームには赤い四角形があり、 x_ref
に可変性オプションがないことを示しています。では、なぜ参照する値を変更できるのでしょうか?
let x_ref = &mut x
のスキームに戻りましょう。
最初の白いブロックには、 x_ref
という名前が含まれています。 2 番目のメッセージは、その変数に格納されている型について通知します。暗黙的な型アノテーションのない完全な形式では、次のように記述できます。
let x_ref: &mut i32 = &mut x;
これは次のように解釈できますi32
への変更可能な参照を保持するx_ref
という名前の不変変数を作成し、 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;
…私はこれを、ステートメントを 2 つのサブステートメント (左と右) に分割する分割線 (特に 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 での代入をよりよく理解できます。このシンプルな視覚化により、多くの混乱が解消されます。
コーディングを楽しんでください!