&mut は Copy trait を 実装していない 。よって、こちらは実行できない。
fn main() { let x: &mut i32 = &mut 0; { let y = x; println!("y: {}", y); } println!("x: {}", x); }
Compiling playground v0.0.1 (/playground)
error[E0382]: borrow of moved value: `x`
--> src/main.rs:7:23
|
2 | let x: &mut i32 = &mut 0;
| - move occurs because `x` has type `&mut i32`, which does not implement the `Copy` trait
3 | {
4 | let y = x;
| - value moved here
...
7 | println!("x: {}", x);
| ^ value borrowed here after move
error: aborting due to previous error
For more information about this error, try `rustc --explain E0382`.
error: could not compile `playground`.
To learn more, run the command again with --verbose.
しかし、なぜかこっちは実行できる。
fn main() { let x: &mut i32 = &mut 0; { let y: &mut i32 = x; println!("y: {}", y); } println!("x: {}", x); }
ブロックを無くして、 x と y を共存させると、コンパイルできなくなる。
fn main() { let x: &mut i32 = &mut 0; let y: &mut i32 = x; println!("x + y: {}", *x + *y); }
Compiling playground v0.0.1 (/playground)
error[E0503]: cannot use `*x` because it was mutably borrowed
--> src/main.rs:4:27
|
3 | let y: &mut i32 = x;
| - borrow of `*x` occurs here
4 | println!("x + y: {}", *x + *y);
| ^^ -- borrow later used here
| |
| use of borrowed `*x`
error: aborting due to previous error
For more information about this error, try `rustc --explain E0503`.
error: could not compile `playground`.
To learn more, run the command again with --verbose.
cannot use *x because it was mutably borrowed という不穏なメッセージが出ている。これは、 y に代入しているものが &mut *x であることを暗に示している。実際、最初の例を以下のようにすると実行可能になる。
fn main() { let x: &mut i32 = &mut 0; { let y = &mut *x; println!("y: {}", y); } println!("x: {}", x); }
この振る舞いを調べると、どうやら reborrow と言われている振る舞いであることがわかった。しかし、現時点で reborrow について明示的にドキュメントされてないらしく、以下の issue が上がっている。
もっとも、この挙動はレシーバが &mut self であるようなメソッドから、同様にレシーバが &mut self であるメソッドを複数回呼ぶだけで自然に発生する(ただ、メソッドのレシーバは auto dereference が効くので、特殊な気もするが)もので、特筆しなくても常識だろうということなのかもしれない。とはいえ、 Copy じゃない割に move しているようにも見えなくて腹落ちしてなかったので、そこがはっきりしたのは調べた甲斐はあった。