Rustのドキュメントで見た2つの関数シグネチャは次のとおりです。
fn modify_foo(mut foo: Box<i32>) { *foo += 1; *foo }
fn modify_foo(foo: &mut i32) { *foo += 1; *foo }
mut
の配置が異なるのはなぜですか?
最初の関数は次のようにも宣言できるようです
fn modify_foo(foo: mut Box<i32>) { /* ... */ }
mut foo: T
は、foo
であるT
という変数があることを意味します。変数を参照を変更できます:
let mut val1 = 2;
val1 = 3; // OK
let val2 = 2;
val2 = 3; // error: re-assignment of immutable variable
これにより、所有している構造体のフィールドを変更することもできます。
struct Monster { health: u8 }
let mut orc = Monster { health: 93 };
orc.health -= 54;
let goblin = Monster { health: 28 };
goblin.health += 10; // error: cannot assign to immutable field
foo: &mut T
は、(&
)値と(mut
)参照値(構造体の場合はフィールドを含む)を変更できます:
let val1 = &mut 2;
*val1 = 3; // OK
let val2 = &2;
*val2 = 3; // error: cannot assign to immutable borrowed content
ご了承ください &mut
は参照でのみ意味があります-foo: mut T
は有効な構文ではありません。 2つの修飾子(let mut a: &mut T
)、それが理にかなっているとき。
C/C++を使用している場合は、基本的に次のように考えると参考になります。
// Rust C/C++
a: &T == const T* const a; // can't mutate either
mut a: &T == const T* a; // can't mutate what is pointed to
a: &mut T == T* const a; // can't mutate pointer
mut a: &mut T == T* a; // can mutate both
これらは互いに逆であることがわかります。 C/C++は「ブラックリスト」アプローチを採用しています。つまり、何かを不変にしたい場合は明示的にそうする必要がありますが、Rustは「ホワイトリスト」アプローチを採用します。変更可能であることを明示的に言う必要があります。