Rust the book 要約 ４章：所有権を理解する


## 目次
  - [4.0 概要](#40-概要)
  - [4.1 所有権とは](#41-所有権とは)
    - [所有権の規則](#所有権の規則)
      - [例１: str 型](#例１-str-型)
      - [例２：ヒープに値を保持する場合（String型）](#例２ヒープに値を保持する場合string型)
    - [二重解放エラーを防ぐ仕組み（ムーブセマンティクス）](#二重解放エラーを防ぐ仕組みムーブセマンティクス)
      - [例：String型の変数のムーブの挙動](#例string型の変数のムーブの挙動)
    - [ヒープ領域内のデータを複製する方法（クローン）](#ヒープ領域内のデータを複製する方法クローン)
    - [スタックのみのデータの複製（コピー）](#スタックのみのデータの複製コピー)
    - [所有権と関数](#所有権と関数)
      - [例：所有権と関数](#例所有権と関数)
    - [戻り値とスコープ](#戻り値とスコープ)
      - [例：戻り値とスコープ](#例戻り値とスコープ)
  - [4.2 参照と借用](#42-参照と借用)
    - [参照](#参照)
    - [参照と関数](#参照と関数)
    - [可変参照](#可変参照)
    - [参照についてのルール](#参照についてのルール)
  - [4.3 スライス型](#43-スライス型)

## 4.0 概要
- 所有権とは
- 参照
- 借用
- スライス
- コンパイラはデータをメモリにどう配置するか

## 4.1 所有権とは
所有権は「**ヒープ領域にメモリ領域を確保**したり、それを**解放する**機能を言語側で管理するための概念」<br>
所有権により以下が可能になる
- どの部分のコードがどのヒープ上のデータを使用するかの把握
- ヒープ上のデータの重複の最小化
- メモリ不足の防止

> ### コラム: 「スタックとヒープ」
> #### スタック
> - コンパイル時に必要メモリサイズが分かっているデータを保持
> - データは固定長
> - 得た順にデータを並べ、逆順で取り除く
> #### ヒープ
> - コンパイル時には必要メモリサイズが不明なデータを保持
> - OS が管理
> - OS に、ある大きさのメモリ領域をヒープ領域に確保するよう依頼すると、OS はメモリ領域を確保したのちに、そのメモリ領域のベースアドレスを返す
> - そのポインタを指定してオブジェクトの破棄をOSに依頼すると、メモリ領域が解放され、貸出可能状態に戻る

### 所有権の規則
- Rust の**各値は、所有者と呼ばれる変数と対応**している。
- いかなる時も**所有者は一つ**である。
- **所有者がスコープから外れたら、値は破棄**される。

#### 例１: str 型
```rust
{
  // *1
  let s = "hello"; // *2
  // *3
} // *4
```

- 上記のコード内で変数`s` にはプログラムにハードコードされた`"hello"`という文字列への参照が束縛される
- この文字列への参照は、`s` が宣言された行 (*2 の時点) から `s` がスコープから抜けるまで (*3 まで) はメモリ上に存在するが、それ以外の領域では存在しない

#### 例２：ヒープに値を保持する場合（String型）
```rust
{
  // *1
  let s = String::from("hello"); // *2
  // *3
} // *4
```
上記のコードでは
- 変数 `s` の宣言時に OS に（ヒープ領域内での）メモリ領域の確保が依頼され
- 確保された領域のベースアドレスなどの情報（ pointer, size, capacity ）が `s` に束縛される
- `s` に束縛された値は *2 ~ *3 の範囲ではメモリ上に存在するが、それ以外の領域では存在しない
- また、ヒープ領域に確保されたメモリ領域は `s` がスコープを抜けると同時に解放される
  - より厳密には、以下のような仕組みになっている：
    - Rust では、閉じ括弧 `}` が自動的に（該当スコープで有効なすべての（`Drop`トレイトが有効な）変数の） `drop` 関数を呼び出す
    - `drop` はその変数と結びついたヒープ領域内のメモリ領域を解放するよう定義されている

### 二重解放エラーを防ぐ仕組み（ムーブセマンティクス）
- Rust では**２つ以上の異なる変数に、同じヒープ領域へのポインタが束縛されることはない**
  - ヒープ領域と結びついたある変数 `a` をほかの変数 `b` に代入 `let b = a` すると、`a` はそれ以降無効化される

#### 例：String型の変数のムーブの挙動
```rust
let s1 = String::from("hello");
```
によって
- ヒープ領域内に `b'h'`, `b'e'`, `b'l'`, `b'l'`, `b'o'` の一連のデータが保持され
- このメモリ領域へのポインタがスタック領域に保持されたとする
- この時、このポインタは変数`s1`に束縛される

<img src="https://doc.rust-lang.org/book/img/trpl04-01.svg" width="400">

ここでさらに
```rust
let s2 = s1;
```
とすると
- 変数 `s2` にヒープ領域へのポインタが束縛され
- 変数 `s1` は無効化される

<img src="https://doc.rust-lang.org/book/img/trpl04-04.svg" width="400">

- 無効化された変数を利用しようとするとコンパイルエラーが発生する
- たとえば以下のコードコンパイルエラーを起こす
  ```rust
  let s1 = String::from("hello");
  let s2 = s1; // この時点で s1 は無効化される
  println!("s1: {}, s2: {}", s1, s2);
  ```

### ヒープ領域内のデータを複製する方法（クローン）
- スタック上のデータだけではなくヒープ領域内のデータの deep copy が必要なら `clone` メソッドを用いる
- たとえば以下のコードは問題なく動く
  ```rust
  let s1 = String::from("hello");
  let s2 = s1.clone(); // clone メソッドを使うことでヒープ領域上のデータごと複製されるため、s1 は破棄されない
  println!("s1: {}, s2: {}", s1, s2);
  ```

### スタックのみのデータの複製（コピー）
- スタック上で完結するデータ型には `Copy` トレイトが実装されていることが期待される
- `Copy` トレイトが実装された型の値はムーブされずにコピーされる
- `Drop` トレイトを実装した型、もしくは `Drop` トレイトを実装した型を一部に含む型には `Copy` トレイトの実装ができない（コンパイルエラーを起こす）
- 以下は自動的に `Copy`
  - スカラー型
  - `Copy` の型だけを含むタプル

### 所有権と関数
- 関数に変数を渡すと、その変数のもつ所有権が関数内に移動する
  - 変数を別の変数に代入した場合と同様に、あるヒープ領域と結びついた変数 `a` を関数 `f` に渡す（ つまり`f(a)`のようにする） と、`a` はそれ以降無効化される

#### 例：所有権と関数
```rust
fn main() {
  let s = String::from("hello");          // sがスコープに入る
  takes_ownership(s);                     // sの値が関数にムーブされ...

                                          // ...ここではもう有効ではない
                                          // ここで s を呼び出そうとすると、コンパイラは、コンパイルエラーを投げる

  let x = 5;                              // xがスコープに入る
  makes_copy(x);                          // xも関数にムーブされるが、
                                          // i32はCopyなので、この後にxを使っても大丈夫

}                                         // ここでxがスコープを抜け、sもスコープを抜ける。
                                          // ただし、sの値はムーブされているので、何も特別なことは起こらない。

fn takes_ownership(some_string: String) { // some_stringがスコープに入る。
  println!("{}", some_string);
}                                         // ここでsome_stringがスコープを抜け、`drop`が呼ばれる。後ろ盾してたメモリが解放される。


fn makes_copy(some_integer: i32) {        // some_integerがスコープに入る
  println!("{}", some_integer);
}                                         // ここでsome_integerがスコープを抜ける。何も特別なことはない。
```

### 戻り値とスコープ
- 関数が値を返すことでも、所有権は移動する

#### 例：戻り値とスコープ
```rust
fn main() {
  let s1 = gives_ownership();                         // gives_ownership は、戻り値をs1にムーブする
  
  let s2 = String::from("hello");                     // s2がスコープに入る
  let s3 = takes_and_gives_back(s2);                  // s2は takes_and_gives_back にムーブされ
                                                      // 戻り値もs3にムーブされる

}                                                     // ここで、s3はスコープを抜け、ドロップされる。
                                                      // s2もスコープを抜けるが、ムーブされているので、
                                                      // 何も起きない。s1もスコープを抜け、ドロップされる。
  
fn gives_ownership() -> String {                      // gives_ownership は、戻り値を呼び出した関数にムーブする
  let some_string = String::from("hello");            // some_string がスコープに入る
  some_string                                         // some_string が返され、呼び出し元関数にムーブされる
}

// takes_and_gives_back は、Stringを一つ受け取り、返す。
fn takes_and_gives_back(a_string: String) -> String { // a_stringがスコープに入る。
  a_string                                            // a_stringが返され、呼び出し元関数にムーブされる
}
```

## 4.2 参照と借用
### 参照
- 変数 `hoge` の参照は `&hoge` で取得できる
- 型 `Hoge` の変数の参照の型は `&Hoge` となる
- `&hoge` には `hoge` へのポインタ（＝「`hoge` に束縛された（ヒープデータへの）ポインタ」へのポインタ）が束縛される
- `&hoge` がスコープを抜けても `hoge` に結びついたヒープデータはドロップされない
- `&hoge` がスコープを抜けても `hoge` に束縛された（ヒープデータへの）ポインタはドロップされない
- `&hoge` がスコープを抜けると `&hoge` 束縛された `hoge` へのポインタが消去される
- 参照外し演算子 `*` で参照を外せる

- 例：以下のコードに登場する `s` とその参照 `s = &s1` の関係は下図の通り；
  ```rust
  fn main() {
    let s1 = String::from("hello");
    let len = calculate_length(&s1);

    println!("The length of '{}' is {}.", s1, len);
  }

  fn calculate_length(s: &String) -> usize {
    s.len()
  }
  ```
  <img src="https://doc.rust-lang.org/book/img/trpl04-05.svg" width="600">

### 参照と関数
- 関数の引数に参照を取ることを借用と呼ぶ

### 可変参照
- 参照はデフォルトではimmutable(不変)
- 可変変数 `hoge` の可変参照は `&mut hoge` で取得できる
- 例：
  ```rust
  fn main() {
    let mut s = String::from("hello");

    change(&mut s);
  }

  fn change(some_string: &mut String) {
    some_string.push_str(", world");
  }
  ```

### 参照についてのルール
> **「参照は、一つの可変参照か複数の不変参照」**<br/>
> **「ダングリング参照は許されない」**<br/>

**1. 一つのスコープ内では、一つのデータに対して、一つしか可変な参照を作れない**
- このルールにより、複数のポインタが同じデータに同時にアクセスすることで発生する問題などを防げる
- 例１：以下のコードはコンパイルエラーを起こす
  ```rust
  let mut s = String::from("hello");
  
  let r1 = &mut s;
  let r2 = &mut s;
  println!("{}, {}", r1, r2);
  ```
- 例２：以下のコードは問題なく動く
  ```rust
  let mut s = String::from("hello");
  {
    let r1 = &mut s;
  } // r1はここでスコープを抜けるので、問題なく新しい参照を作ることができる
  
  let r2 = &mut s;
  ```

**2. 不変参照と可変参照は同一スコープ内で共存できない** <br/>
**3. 不変参照は複数共存可能**
- 以下のコードはコンパイルエラーを起こす
  ```rust
  let mut s = String::from("hello");

  let r1 = &s; // 問題なし
  let r2 = &s; // 問題なし
  let r3 = &mut s; // 問題あり！
  ```

**4. ダングリング参照はコンパイラエラーで阻止される**
- 以下のコードはコンパイルエラーを起こす
  ```rust
  fn main() {
    let reference_to_nothing = dangle();
  }

  fn dangle() -> &String {
    let s = String::from("hello");

    &s
    // ここで s はドロップされる
    // --> ドロップ済みの値への参照をこの関数の外側にムーブしようとしていることになる
    // --> 無効な参照を作る不法な操作なのでコンパイラに怒られる
  }
  ```

## 4.3 スライス型
- スライスにより、コレクション全体ではなく、その内の一連の要素を参照することができる
- スライスは、`&hoge[1..3]` のような形で取得する
- スライスは、元のコレクションオブジェクトの不変参照である
- スライスは、通常の参照と異なり、スタック上のポインタへのポインタではなく、ヒープデータへのポインタを保持する
  - 内部的には先頭へのポインタと長さを保持する（下図は、`s = String::from("hello world")`, `world = &s[6..]` を示す）
    <img src="https://doc.rust-lang.org/book/img/trpl04-06.svg" width="400">

- このような成り立ちのために、スライスのスライスはスライスである（型は変わらない）
  - ただし、元のコレクションオブジェクトとは型が異なる
    - たとえば、`String` 型に対するスライスは `&str`, `&str` のスライスは `&str`
    - たとえば、`[i32; 10]` 型に対するスライスは `&[i32]`, `&[i32]` のスライスは `&[i32]`
- 一方、`Hoge`　型の変数への参照は `&Hoge` であり、その参照への参照は `&&Hoge` であるので注意

  ```rust
  // `String` のスライスは `&str`
  // `&str` のスライスは `&str`
  fn main() {
      let s: String = String::from("hello");
      let slice: &str = &s[1..4];     // ell
      let slice: &str = &slice[1..];  // ll
      let slice: &str = &slice[..1];  // l

      println!("slice: {}", slice);
  }
  ```

  ```rust
  // `[i32; 10]` のスライスは `&[i32]`
  // `&[i32]` のスライスは `&[i32]`
  fn main() {
      let a:[i32; 10] = [1, 2, 3, 4, 5, 1, 2, 3, 4, 5];
      let slice: &[i32] = &a[1..9];     // [2, 3, 4, 5, 1, 2, 3, 4]
      let slice: &[i32] = &slice[..7];  // [2, 3, 4, 5, 1, 2, 3]
      let slice: &[i32] = &slice[3..];  // [5, 1, 2, 3]
      println!("slice: {:?}", slice);
  }
  ```

  ```rust
  // `String` の参照は `&String`,
  // `&String` の参照は `&&String`
  fn main() {
      let s: String = String::from("hello");
      let s: &String = &s;
      let s: &&String = &s;
  }
  ```

- また、`&&..&Hoge` のスライスを取るのと、`Hoge` のスライスを取るのは同等らしい（Rust 側で参照外しをやってくれるっぽい？）
  ```rust
  fn main() {
      let s: String = String::from("hello");
      let s: &String = &s;
      let s: &&String = &s;
      let s: &&&String = &s;
      let slice: &str = &s[1..4];     // ell

      println!("slice: {}", slice);
  }
  ```

## 参考文献

- [The Rust Programming Language 日本語版](https://doc.rust-jp.rs/book-ja/ch04-00-understanding-ownership.html)