jpnykw’s blog

軽率なアウトプットをします

Rustの所有権について

今回はRustの借用/参照と所有権について雑に書きなぐる.

所有権とは

所有権はRustに導入されているゼロコスト抽象化*1の例の一つ. 具体的な例を上げると, 変数が非primitiveな型*2である場合に, 以下のような問題に直面する.

fn some(x: Vec<i8>) {
  // TODO:
}

fn main() {
  let x = vec![2];
  some(x);
  println!("{:?}", x);
}

この処理を実行してみる. 内容は順にxにVectorを代入して, xの中身をprintlnで表示している. someの中身は重要ではないので無視する. 実行してみると次のようなエラーが発生する.

borrow of moved value: `x`

意訳するとxが移動された後に借用された という意味になる. 実はこの移動されたというのは, 所有権が移動したという意味だ. xの所有権はmain関数のスコープにあった訳だが, some(x) を呼び出した時点で所有権がsomeに移動する. つまり, それ以降からxを参照しようとすると, 所有権がないのでエラーになる.

参照と借用

これを回避するためにはxの所有権を渡すのではなく, xを借用させれば良い.

fn some(x: &Vec<i8>) {
  // TODO:
}

fn main() {
  let x = vec![2];
  some(&x);
  println!("{:?}", x);
}

注意してほしいのが, some関数が引数で受け取る値はVector型ではなく&Vector型であることだ. 即ち各要素の型も&i8になる. こうすることで, xの所有権を渡すこと無く, xの値を参照することが可能だ.

Mutable参照

&mut T を用いることでMutable参照を実現する. この実装によってリソースの変更が可能で, 副作用を持たせることが出来る.

fn main() {
  let mut x = 2;
  {
    let y = &mut x;
    *y = 6;
  }
  println!("{}", x);
}

外側のスコープで宣言したxを &mut 参照を用いてyに引き渡している. アスタリスクを引き渡したyに追加することで, 参照内容であるxにアクセスすることが出来る. 即ちxの値を書き換えることが出来る.

*1:実行時コストを抑えたままに抽象化を実現する仕組み.

*2:primitiveな型にはCopyトレイトが実装されている