【Rust入門】変数の所有権、MoveとCopy

前回は変数の代入(ミューダブル、イミューダブル、シャドーイング)についてやりました。
【Rust入門】ミユーダブル、イミューダブル、シャドーイング

今回はそれと関係のある変数の所有権についてです。

所有権はRustの大きな特徴

変数の所有権はRustの大きな特徴の一つです。
所有権とは何なのか?
以下の例文を見てください。

1
2
3
4
5
6
7
fn main() {
    let name = String::from("hello");
    let name2 = name;
 
    println!("name is {}", name);
    println!("name2 is {}", name2);
}

何気ない例文になりますが、5行目のprintlnでコンパイルエラーになってしまいます。
理由は、nameに”hello”という文字列の所有権が無いためです。

変数の所有権とは?

Rustの変数には所有権という考え方があります。
所有権とは変数の値を書き換えたり参照したりする権利です。

例文では、2行目でnameを宣言して”hello”という文字列を代入した時点では、文字列の所有権はnameにあります。

let name = String::from(“hello”);

しかし、3行目でnameをname2に代入した時点で文字列の所有権はname2に移ってしまい、nameは”hello”という文字列にアクセスすることができなくなります。

let name2 = name;

この変数にアクセスする権利が所有権です。
そして、3行目のように所有権を移動させることを「Move」と言います。

一般的なコンピューター言語では、変数を他の変数に代入すると値がそのままコピーされま。
しかし、Rustは「特定の型の変数以外は」、代入をすると所有権もなくなり、以降はその変数を使うことができなくなります。

所有権のメリットは?

所有権により、変数の書き換えや利用を限定することができます。これにより予想外の場所で値が書き換えられたり使われたりすることを防ぐことができます。

所有権の移動がない特定の型とは?

先程、代入をすると特定の型以外は所有権が移行すると言いましたが、所有権が移行しない特定の型とは何なのでしょうか?
それはプリミティブ型タプル型です。
(タプル型については後ほどやるのでここでは省きます。

プリミティブ型というのは、i32とかu8などのよく使う変数の型です。
詳しくはこちらをご覧ください。
【Rust入門】基本データ型(プリミティブ型)について

これらプリミティブ型の代入では、値がコピーされるだけで、所有権の移行は行なわれません。他の言語の代入と同じです。
このように、所有権の移動がなく、値がコピーされる動作を「Copy」と言います。

1
2
3
4
5
6
7
fn main() {
    let value : i32 = 150;
    let value2 : i32 = value;
 
    println!("name is {}", value);
    println!("name2 is {}", value2);
}

この例では、valueとvalue2はプリミティブ型なので代入しても所有権の移動は行なわれません。
そのため、どちらの変数でもprintlnで値を出力することができます。

文字列はMoveの場合とCopyの場合がある

少し難しいのは文字列の場合です。
文字列はstr型とString型があります。
str型はプリミティブ型なので所有権は移行しません。
反対にString型は所有権が移行します。

[str型]

1
2
3
4
5
6
7
8
9
fn main() {
    let text : &str = "hello";
    //所有権は移動しない
    let text2 : &str = text;
 
    //textもtext2も使える
    println!("name is {}", text);
    println!("name2 is {}", text2);
}

[String型]

1
2
3
4
5
6
7
8
9
fn main() {
    let text : String = String::from("hello");
    //所有権が移動
    let text2 : String = text;
 
    //textは使えない
    println!("name is {}", text);
    println!("name2 is {}", text2);
}

MoveとCopyのまとめ

  • Rusrの変数の代入にはMoveとCopyの2種類がある。
  • Moveは所有権の移行が行われるので、以降はその変数は使えない。Copyはただの値渡しとなる。
  • プリミティブ型とタプル型の代入はCopy、それ以外はMoveになる。