@Deprecated rust入門編01

こんにちは、rustが好きでたまらない初心者のせいです。

最近業務でrustを書くチャンスを頂いて日々楽しくrustコンパイラーと戦っています。
まだ初心者ですが、[The book](https://doc.rust-lang.org/beta/book/title-page.html)を読みながらrustの一番特徴なメモリ管理（所有権、参照＆借用）について
自分の理解でまとめてみました。間違ったところがあったら温かいコメントをいただければと思います。

実行環境：

- rustc --version
  - rustc 1.35.0-nightly (fbd34efb3 2019-03-26)
- edition: 2018

# rustにハマる巻01  

## 1． rustはどんな言語？

  高速かつ安全、多くの設計＆実装ミスなど潜在的なバグはコンパイル時点で検知してくれる言語です。
  
## 2． 色々なメモリの管理仕組み

  - 手動でallocate/free （C、、、他は全然思い付かない）
    - バグ無しで実装することはスーパーエンジニアしかできない
      - freeし忘れたら、memory leak
      - freeが早かったら、予期せぬエラー
      - freeがダブったら、予期せぬエラー
  - garbage collection （Jvm系、Haskellなど）
    - 手抜き、めっちゃ楽
    - Full GCが発生したら再起動しかない
  - 自動的にスコープから外れたら直ちに解放 （**rust**、C++ RAII patterns）

## 3． rustのメモリ管理

#### メモリは用途によって２種類に分類：

| ＼ | Stack | Heap |
|:---|:---|:---|
|**アクセス方法** |LIFO |一定な領域が確保できる任意な場所 |
|**格納対象** |サイズ固定なデータ |サイズ変動可能なデータ |
|-------- | - 全ての整数型（i32, u32など） | - サイズ固定以外のデータ（Stringなど） |
|-------- | - 全ての小数型（f64など） |-------- |
|-------- | - bool, char |-------- |
|-------- | - 上記タイプのみ含むTuple：(i32, bool) |-------- |
|-------- | - 上記タイプのみ含むstruct |-------- |
|-------- | - 所有権 |-------- |

## 4． 所有権

```rust
{                      　　　　　　　  // スコープ開始
    let s1 = String::from("hello");  // 「hello」という文字列の所有権はs1に与えている
    let s2 = String::from("world");  // 「world」という文字列の所有権はs2に与えている
    // s1, s2 は使える
}                                    // スコープ終了、s2->s1という順番で解放する
```

#### 実際メモリに格納したイメージ：

- メモリ解放： Stackにある所有権に従ってHeapも一緒にfreeされる

#### 　　　　Stack　　　　　　　　　Heap
#### 　　　　　↓　　　　　　　　　　　↓

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

### 4-1． 所有権の移譲： 代入

```rust
fn main() {
    let s1: String = String::from("hello");
    {
        let s2: String = s1;     // 所有権はs1からs2に移譲した
    }
    println!("{}, world!", s1);  // s1は無効なのでコンパイルエラーになる
}
```

#### コンパイルエラー: 

```rust
error[E0382]: use of moved value: `s1`
  --> src/main.rs:22:28
   |
20 |         let s2 = s1;
   |             -- value moved here
21 |     }
22 |     println!("{}, world!", s1);
   |                            ^^ value used here after move
   |
   = note: move occurs because `s1` has type `std::string::String`, which does not implement the `Copy` trait
```

#### 実際メモリに格納したイメージ：

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

- rustの思想はheapまでも解放する鍵として**常に１つしかない**ようにコントロールしないといけないことです。
  - 仮にこの例のs1とs2が両方共所有権があるとしたら、s2がスコープ（奥の中括弧）から離れたとき、s1はheapが解放済みの所有権になるので、実行時に予期せぬエラーになります。

### 4-2． 所有権の移譲： function経由

```rust
fn takes_ownership(s: String) {
}

fn main() {
    let s1: String = String::from("hello");
    takes_ownership(s1);                    // 所有権はs1からfunction:takes_ownershipのsに移譲した
    println!("{}, world!", s1);             // s1は無効なのでコンパイルエラーになる
}
```

#### functionを呼び出した後でもs1を使いたい場合はどうすればいいの？

- 一つ方法は所有権を**return経由で返す**

```rust
fn takes_ownership_and_give_back(s: String) -> (String, usize) {
    let length = s.len();
    (s, length)                                        // sで受け取った所有権をそのまま返す
}

fn main() {
    let s1: String = String::from("Oh my god ...");
    let (s1, length) = takes_ownership_and_give_back(s1);  // 分配束縛で文字列の所有権が再び与えられた、s1は同名変数の再宣言
    println!("{} : size({})", s1, length);
}
```

これはやってらんねーな。。。

### 4-3． 所有権の移譲： structの属性

```rust
#[derive(Debug)]
struct Data2 {
    pub value1: String,
    pub value2: String,
}
    
fn main() {
    let data2 = Data2 { value1: "value1".to_string(), value2: "value2".to_string() };
    let data2_value1 = data2.value1;   // 所有権は data2.value1 から移譲した
    println!("{:?}", data2.value1);    // data2.value1 の所有権は失ったため、コンパイルエラーになる
    println!("{:?}", data2.value2);    // 問題なく data2.value2 はアクセスできる
    println!("{:?}", data2);           // data2.value1 の所有権は失ったため、コンパイルエラーになる
}
```

## 5． 所有権を移譲しない： Copy trait と Clone trait

### 5-1． Stackコピー： Copy trait

- サイズ固定なデータ（**Stackのみ使う**）は、所有権の移譲とデータの複製は実質同じ処理になるため、所有権は移譲しない。

```rust
fn main() {
    let i1: i32 = 100;
    {
        let i2: i32 = i1;        // 所有権の移譲は発生せず、i1のcopyをi2に与えた
    }                            // i2のみ解放される
    println!("number: {}", i1);  // i1はそのまま使える
    
    // これも同じく通る
    let t1: (i32, bool) = (1, true);
    {
        let t2: (i32, bool) = t1;
    }
    println!("{}, {}", t1.0, t1.1)
}
```

- サイズ固定な属性しか持ってないstructも同じ

```rust
#[derive(Copy, Clone)]        // サイズ固定な属性しか持ってないstructもCopy traitを実現することができる
struct Data3 {
    pub value1: i32,
    pub value2: char,
}
    
fn main() {
    let d1: Data3 = Data3 { value1: 0, value2: 'a' };
    {
        let d2: Data3 = d1;                    // 所有権の移譲は発生せず、d1のcopyをd2に与えた
    }                                          // d2のみ解放される
    println!("{}, {}", d1.value1, d1.value2);  // d1はそのまま使える
}
```

### 5-2． 完全コピー： Clone trait

```rust
fn main() {
    let s1: String = String::from("hello");
    {
        let s2: String = s1.clone();        // 所有権の移譲は発生せず、s1のcloneをs2に与えた
    }                                       // s2のみ解放される
    println!("{}, world!", s1);             // s1はそのまま使える
}
```

#### 実際メモリに格納したイメージ：

<img src="https://doc.rust-lang.org/book/img/trpl04-03.svg" width="50%">

#### Clone trait の実現：

```rust
#[derive(Clone)]
struct Data {
    pub value: String
}

fn main() {
    let d1: Data = Data { value: String::from("hello, data") };
    {
        let d2: Data = d1.clone();
    }
    println!("{}", d1.value);
}
```

## 6． 所有権を移譲しない： 参照と借用

```rust
fn main() {
    let s1: String = String::from("hello");
    let s: &String = &s1;
    let s: &String = &&&s1;                  // コンパイルOK: s1の参照の参照の参照（やめましょう）
}
```

#### 実際メモリに格納したイメージ：

<img src="https://doc.rust-lang.org/book/img/trpl04-05.svg" width="50%">

- 4-2の問題を参照と借用で解決する

```rust
fn does_not_takes_ownership(s: &String) -> usize {
    s.len()
}

fn main() {
    let s1: String = String::from("hello");
    let length = does_not_takes_ownership(&s1);
    println!("{} : size({})", s1, length);
}
```

### 6-1． Mutableな参照

```rust
fn main() {
    let s1: String = String::from("hello");
    let s: &mut String = &mut s1;
}
```

#### コンパイルエラー: 

```rust
error[E0596]: cannot borrow immutable local variable `s1` as mutable
  --> src/main.rs:75:31
   |
74 |     let s1: String = String::from("hello");
   |         -- help: make this binding mutable: `mut s1`
75 |     let s: &mut String = &mut s1;
   |                               ^^ cannot borrow mutably
```

- Mutableな参照は**Mutableな所有権**からしか借用できない

```rust
fn main() {
    let mut s1: String = String::from("hello");    // Mutableな所有権
    println!("{}", s1);
    {
        let s: &mut String = &mut s1;              // Mutableな参照
        s.push_str(", mut ref");                   // Mutableな参照を使って文字列をappendした
    }
    println!("{}", s1);
}
```

### 6-2． 参照の制限

- **参照の有効スコープは所有権のを超えてはいけない**

```rust
fn main() {
    let s;
    {
        let s1: String = String::from("hello");
        s = &s1;
    }
    println!("{}", s);
}
```

#### コンパイルエラー: 

```rust
error[E0597]: `s1` does not live long enough
   --> src/main.rs:104:14
    |
104 |         s = &s1;
    |              ^^ borrowed value does not live long enough
105 |     }
    |     - `s1` dropped here while still borrowed
106 |     println!("{}", s);
107 | }
    | - borrowed value needs to live until here
```

- **参照とMutableな参照は同時に混在できない**
  - edition-2018の[Non-lexical lifetimes](https://doc.rust-lang.org/edition-guide/rust-2018/ownership-and-lifetimes/non-lexical-lifetimes.html)の場合、ライフタイムが広い方が使われるまでの間に、他の参照またはmut参照が宣言されたらコンパイルエラーになる
  - edition-2018の場合、下記の例だと、s2とs3の宣言順番が逆にしたらコンパイルエラーにはならない

```rust
fn main() {
    let mut s1: String = String::from("hello");
    let s2: &String = &s1;
    let s3: &mut String = &mut s1;
    println!("{}", s2);
}
```

#### コンパイルエラー: 

```rust
error[E0502]: cannot borrow `s1` as mutable because it is also borrowed as immutable
  --> src/main.rs:95:27
   |
94 |     let s2: &String = &s1;
   |                       --- immutable borrow occurs here
95 |     let s3: &mut String = &mut s1;
   |                           ^^^^^^^ mutable borrow occurs here
96 |     println!("{}", s2);
   |                    -- immutable borrow later used here
```

- **Mutableな参照は同時に複数存在できない**
  - edition-2018の[Non-lexical lifetimes](https://doc.rust-lang.org/edition-guide/rust-2018/ownership-and-lifetimes/non-lexical-lifetimes.html)の場合、ライフタイムが広い方が使われるまでの間に、他のmut参照が宣言されたらコンパイルエラーになる
  - edition-2018の場合、下記の例だと、s2とs3の宣言順番が逆にしたらコンパイルエラーにはならない

```rust
fn main() {
    let mut s1: String = String::from("hello");
    let s2: &mut String = &mut s1;
    let s3: &mut String = &mut s1;
    s2.push_str(", error occur here");
}
```

#### コンパイルエラー: 

```rust
error[E0499]: cannot borrow `s1` as mutable more than once at a time
   --> src/main.rs:100:27
    |
99  |     let s2: &mut String = &mut s1;
    |                           ------- first mutable borrow occurs here
100 |     let s3: &mut String = &mut s1;
    |                           ^^^^^^^ second mutable borrow occurs here
101 |     s2.push_str(", error occur here");
    |     -- first borrow later used here
```

## 7． 特別な参照： Slice

#### Sliceを使用すると、コレクション全体だけではなく、コレクション内の一部連続した要素も参照できる。
#### SliceはStackに格納されるため、コレクションのサイズは固定になる。

### 7-1． 文字列Slice： &str

```rust
fn main() {
    let s: &str = "hello";                   // 文字列リテラルは&strである
    let s1: String = String::from("hello");
    let ss1: &str = s1.as_str();             // => 「hello」の参照
    let ss1: &str = &s1[..];                 // => 「hello」の参照
    let ss1: &str = &s1[2..4];               // => 「hello」の「ll」部分の参照
    let ss1: &str = &s1[2..=4];              // => 「hello」の「llo」部分の参照
}
```

### 7-2． &str vs &String

| 自動キャスト | 結果 |
|:---|:---|
|&String -> &str |OK |
|&str -> &String |NG |

```rust
fn takes_ref_str(s: &str) {}

fn takes_ref_string(s: &String) {}

fn main() {
    takes_ref_str(&s1);
    takes_ref_str(s1.as_str());
    takes_ref_string(&s1);
    takes_ref_string(s1.as_str());       // ここだけコンパイルエラーになる
}
```

#### コンパイルエラー: 

```rust
error[E0308]: mismatched types
   --> src/main.rs:132:22
    |
132 |     takes_ref_string(s1.as_str());
    |                      ^^^^^^^^^^^ expected struct `std::string::String`, found str
    |
    = note: expected type `&std::string::String`
               found type `&str`
```

### 7-3． その他のSlice

```rust
fn main() {
    let s_i32: &[i32; 3] = &[1, 2, 3];
}
```

## 8． インスタンスメソッド

```rust
#[derive(Debug)]
struct Object {
    pub data: String,
}

impl Object {
    fn takes_self(self) {}

    fn takes_ref_self(&self) {}

    fn takes_ref_mut_self(&mut self) {
        self.data.push_str(", &mut self")
    }
}

fn main() {
    let o1 = Object { data: "hello".to_string() };
    o1.takes_self();
    println!("{:?}", o1);                          // ここだけコンパイルエラーになる

    let o2 = Object { data: "hello".to_string() };
    o2.takes_ref_self();
    println!("{:?}", o2);

    let mut o3 = Object { data: "hello".to_string() };
    o3.takes_ref_mut_self();
    println!("{:?}", o3);
}
```

#### コンパイルエラー: 

```rust
error[E0382]: use of moved value: `o1`
   --> src/main.rs:146:22
    |
145 |     o1.takes_self();
    |     -- value moved here
146 |     println!("{:?}", o1);
    |                      ^^ value used here after move
    |
    = note: move occurs because `o1` has type `Object`, which does not implement the `Copy` trait
```