&mut 型と let mut の違い
ふと気になってしまったため
🎵 今日に一曲は、ひとくちメモでは廃止します
ストックする曲数が減ってしまったため、廃止します。
mut について
イミュータブルをミュータブルにするあれです。
let
式にmut
という語をつけると、値を束縛した変数がミュータブル(変更可能)となります。
&mut 型について
fn main() { // 生の値 let mut i = 32; println!("{}", i); // 可変参照の値 let m = &mut i; *m = 64; println!("{}", i); }
&mut
は、可変参照であることを示す。 *
は参照外し記号である。
*
を&mut
に用いると、その一瞬だけ、生の値が見えるようになる。
let m = &mut i; // mはiの可変参照
let x = *m; // xとiは別物になる
別の変数で束縛すると、clone したという扱いとなり、別の値になってしまう。
let m = &mut i; // mはiの可変参照
*m = 64;
ここでは、
i = 64
と同義となる。
note
本来参照が不要なところで使用しているため。
参照が必要なところでこれを行うと、値を move してしまい、元のスコープで継続して使用できなくなってしまう
可変参照の制約
// 可変参照の値
let m = &mut i;
let n = &mut i; // mが無効になる
*m = 64; // mは無効なのでエラー
可変参照は、言語の制約によって参照が一つまでに制限される。 よって、上記のように宣言するのは NG だし
#![allow(unused)] fn main() { // 可変参照の値 let m = &mut i; *m = 64; println!("{}", i); // mの参照がまだ残ってるので、新たに参照が作れない *m = 128; }
別の関数を呼び出すことによって、参照を無効化してしまう恐れもある。
コンパイラー曰く「m の参照が残ってるので新たに参照が作れない」となるらしい。
可変変数の可変参照
fn main() { let mut x:i32 = 0; let mut y:i32 = 0; let mut z:f64 = 0.0; let mut edit: &mut i32 = &mut x; *edit = 3; edit = &mut y; *edit = 6; edit = &mut z; *edit = 9.0; println!("x: {}, y: {}, z: {}", x, y, z); }
これが一番ややこしい例です。可変変数に可変参照を束縛しているという状態です。
edit 変数は i32 型の可変参照を持つため、x,y と参照を変えながら、各値を変えています。
しかし、z は f64 型なので、コンパイルエラーとなります。
fn main() { let mut x:i32 = 0; let mut y:i32 = 0; let mut edit: &mut i32 = &mut x; *edit = 3; edit = &mut y; *edit = 6; println!("x: {}, y: {}", x, y); }
z を取り除くと、コンパイルに成功します。
なお、こういうのもありということです。
fn main() { let mut x:i32 = 0; let mut y:i32 = 0; let edit: &mut i32 = &mut x; *edit = 3; let edit: &mut i32 = &mut y; *edit = 6; println!("x: {}, y: {}", x, y); }
edit が可変でなくとも参照が可変なので、値の変更が可能です。
とてもややこしい。