paint-brush
変更可能な参照または変更可能な変数? Rustのmut-mut-mutをデコードする@charnog
883 測定値
883 測定値

変更可能な参照または変更可能な変数? Rustのmut-mut-mutをデコードする

Denis Gonchar5m2023/09/23
Read on Terminal Reader

長すぎる; 読むには

Rust のメモリの安全性は、その所有権と借用のメカニズムに根ざしています。この記事では、可変参照と可変変数を区別しながら、mut キーワードの複雑さを詳しく掘り下げます。重要なポイントは何ですか?すべての mut が同じように作成されるわけではありません。可変参照ではポイント先の値を変更できますが、参照を持つ可変変数ではポイント先が変更される可能性があります。 = 記号を使用した便利な視覚化トリックにより、これらの違いを簡単に理解できます。
featured image - 変更可能な参照または変更可能な変数? Rustのmut-mut-mutをデコードする
Denis Gonchar HackerNoon profile picture

イントロ

Rust は Rust ブックを提供していますが、私はmutキーワードを理解するのに苦労しました。 「この問題を抱えているのは私だけでしょうか?」と自問しました。 Google で簡単に検索したところ、私が一人ではないことがわかりました。


その結果、 mutキーワードについて詳しく説明するためにこの記事を書くことにしました。この記事は、Python や JavaScript などの高級言語を使用するユーザーを対象としています。

変数

Rustで変更不可能な変数を作成するには、単にlet x = 1337と書くだけです。それは簡単です。後で変更できる変数を作成したい場合は、 letの後にmutキーワードを追加するだけです。 Rust には、意図を明確にするための便利な規約があります。


mutキーワードを追加すると、この変数がコード内の別の場所で変更されることが他の人に通知されます。わかった。


それを視覚化してみましょう。ここでは 2 つの変数、 let mut x = 1337およびlet y = 42

ファーストネーム; 2 番目 - タイプ、3 番目 - 値、4 番目 - mut フラグ。

参考文献

現時点では、すべてが簡単です。ただし、 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のインスタンスが多すぎますよね?それらについて説明しましょう。


  1. let mut x_ref : x_refという名前の可変変数を作成しています。これは、後でその値を変更できることを意味します。


  2. &mut i32 : 変数にはi32型の値への変更可能な参照が含まれると述べています。


  3. &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 での代入をよりよく理解できます。このシンプルな視覚化により、多くの混乱が解消されます。


コーディングを楽しんでください!