&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 しているようにも見えなくて腹落ちしてなかったので、そこがはっきりしたのは調べた甲斐はあった。