Rust言語の所有権とは

## Rust言語での所有権について
### 前提
***
プログラミング言語の世界では、オブジェクトとはメモリ領域を使用して何らかのデータを保持するもの、またはそのメモリ領域自体を指します。
Rustではオブジェクトはスタック上に確保される自動変数、動的に確保されるヒープ変数、データセグメントに固定で配置される静的変数の３つがあります
<dl>
  <dt>自動変数</dt>
  <dd>関数やブロック内でlet 文で宣言されるプリミティブ変数</dd>
  <dt>ヒープ変数</dt>
  <dd>構造体、ボックス、コレクションなどの実行時に動的に割り当てる変数</dd>
  <dt>静的変数</dt>
  <dd>プログラム実行中に使用可能な大域変数<dd>
</dl>

このうち自動変数はプログラムの実行がブロックの外に出たところでメモリ領域が解放されますが、ヒープ領域については既存のプログラム言語ではプログラムで明示的に開放するステップを記述するか、ガベージコレクタ（GC）という機構を利用する必要がありました。

Rustではプログラムでのメモリの解放忘れや二重解放、GCによるパフォーマンス劣化といった問題を解決するために、オブジェクト（データメモリ領域）のライフタイム管理を行うために「所有権」、「借用」、「ライフタイム」という機構を用意し、上記の問題を解決しています。

最も重要なのが、メモリオブジェクトに対して一つの変数にしか所有権を与えないということです。その変数の使用が終了した時点でプログラム内ではその使用者がいなくなるため、その時点でメモリオブジェクトを開放できることになります。
Rustではソースコードのコンパイル時点でそのタイミングを知ることができるため、実行時のオーバヘッドを最小限に減らし、メモリリークや二重解放によるシステムエラーを完全に回避することができます。

では、この唯一の所有権をどのように実現しているかプログラムのステップと図を例にして見てみましょう

### 変数とオブジェクトの関係
***
変数とオブジェクトの関係を図示すると以下の様になります。
#### 1. 自動変数(プリミティブ型)
``` rust
let a = 1;
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4107100/cae4c6ac-e1c0-412f-a33d-dd10237984be.png)
#### 2. 自動変数（構造体)
``` rust
struct Point {
    x: i32,
    y: i32,
}

let p = Point { x: 10, y: 20 };
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4107100/9460d6b8-1634-40ba-9513-c597c7de49a0.png)
#### 3. ヒープ変数（コレクション:ベクトル）
``` rust
let v = vec![1,100,1000];
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4107100/851fd2a3-2670-4bed-bd44-e846856f635f.png)
#### 4. ヒープ変数（ボックス）
``` rust
let h = Box::new(123);
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4107100/eb294106-7a39-449c-852b-c9c8fa506599.png)


### 所有権の移動
***
#### 1. プリミティブ型の自動変数の代入
``` rust
let a = 1;
let b = a;
println!("a = {}, b = {}" , a, b);
```
プリミティブ型の自動変数を代入する場合、値をコピーしたスタック領域を用意することになり所有権の移動は発生しません。
1行目では変数aの領域が確保されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4107100/362cdd45-eafa-4bc5-81c1-1ff3d5245573.png)
1行目では変数bの領域が確保され、aの値がコピーされます。結果としてaとbはメモリ上で独立した別のオブジェクトです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4107100/be174c6a-65a5-4b13-a32e-1f0dc7b34c76.png)
#### 2. 構造体を自動変数として宣言して代入
``` rust
struct Point {
    x: i32,
    y: i32,
}

let p = Point { x: 10, y: 20 };
let q = p;
println!("p =({}, {}), q =({}, {})" , p.x, p.y, q.x, q.y);
```
スタック上のオブジェクトとして確保された構造体を代入した場合は、プリミティブ型の場合と異なり所有権の移動が発生します。
6行目でpを宣言したときは以下のような状態です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4107100/80f72616-dd32-4018-8b26-a5184cd47d8e.png)
7行目でqを宣言し、pを代入すると以下のような状態になります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4107100/63273f39-c340-49a7-b343-017283fc778a.png)
したがって、上記のprintln!()のステップは以下のエラーが発生します。
``borrow of moved value: `p` ``
`value borrowed here after move`
これは、変数pはqに代入した時点でオブジェクトの所有権がpからqに移動したため変数pへの参照は無効となってしまったためです。

:::note
構造体についてはコンパイラの処理によって新たにqの実体をもう一つ確保し、pを無効化するようなコードを生成する可能性もあります。
:::
#### 3. ベクトルの代入
``` rust
let v = vec![1,100,1000];
let w = v;
println!("v={:?}, w={:?}", v, w);
```
コレクションオブジェクトとしてヒープ領域の変数を代入した場合は、所有権の移動が発生します。
このプログラム例では1行目の実行後、以下の様になっています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4107100/8c7bc037-9743-4cdf-8e35-c2b6c7965776.png)
2行目でvをwに代入すると、以下の図のようにオブジェクトの所有権はw移動し、結果として変数vは無効となります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4107100/fc13be24-4c98-468b-9117-03d78ddc21e3.png)
したがって、上記のprintln!()のステップは以下のエラーが発生します。
``borrow of moved value: `v` ``
`value borrowed here after move`
#### 4. ボックスの代入
``` rust
struct Point {
    x: i32,
    y: i32,
}

let p = Box::new(Point{x:10, y:20});
let q = p;
println!("p({},{}),q({},{})", p.x, p.y, q.x, q.y);
```
Box変数はオブジェクトをヒープ領域に作成します。
6行目では以下のような状態になっています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4107100/e1f71d02-de55-452a-a318-43abb1ad6f77.png)
2行目でpをqに代入すると、以下の図のようにオブジェクトの所有権はqに移動し、結果として変数pは無効となります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4107100/a80da35f-8ac1-4c16-b0bf-1fc4eb8cc329.png)
したがって、println!()のステップは以下のエラーが発生します。
``borrow of moved value: `p` ``
`value borrowed here after move`