The Rust Programming Languageを読み進める（4章）

# はじめに

The Rust Programming Languageを頭から読み進めてみる。読みながら要点をまとめていった記事です。

* [The Rust Programming Languageを読み進める（1〜2章）](https://qiita.com/yktooo/items/df17496b38b1b5c49aba)
* [The Rust Programming Languageを読み進める（3章）](https://qiita.com/yktooo/items/481d49f248cb9947af81)

# 4章：所有権を理解する
## 4.1章：所有権とは？
https://doc.rust-jp.rs/book-ja/ch04-01-what-is-ownership.html
### スタックとヒープ
* スタック
    * 後入れ先出しのため、データの場所を考える必要がない
    * 高速だが、サイズは既知である必要がある
* ヒープ
    * 配置場所に規則はなく、空いている場所を探す
    * スタックより低速だが、サイズは可変で良い

### 所有権規則
* Rustにおける所有権とは、メモリを安全に管理するための仕組み
    * Rustの値は、保有者と呼ばれる変数と対応
    * いかなる時も所有者は1つ
    * 所有者がスコープから外れたら値は破棄
        * `drop`関数が呼ばれ、メモリが解放

### 所有権のムーブ
```rust
fn main() {
    let s1 = String::from("hello");
    let s2 = s1;
    println!("The Value s2 is: {}", s2);
    
    // Error
    // println!("The Value s1 is: {}", s1); 
} 
```
```
The Value s2 is: hello
```
* `s1`を定義すると、文字列の中身を保持するメモリへのポインタ、長さ、および許容量が**スタックに保持される**。そして、ポインタの先にある"hello"は、**ヒープ上のメモリに保持される**。
* `s2 = s1`で代入されると、データがコピーされるが、ポインタが指すヒープ上のデータはコピーしない 
* `s1`, `s2`両方が生存していると、2回メモリ解放を繰り返すことになるので、`s2 = s1`の時点で**所有権がムーブされる**（以下画像の状態）
* 所有権のムーブ後は`s2`だけが有効のため、スコープを抜けると`s2`だがメモリが開放される
* **Rustはデータのdeep copyは設計上無い**とのこと

[<img width=400 src = "https://doc.rust-jp.rs/book-ja/img/trpl04-04.svg">](https://doc.rust-jp.rs/book-ja/img/trpl04-04.svg) 
The Rust Programming Language 日本語版 図4-3から引用

### クローン
```rust
fn main() {
    let s1 = String::from("hello");
    let s2 = s1.clone();
    
    println!("s1 = {}, s2 = {}", s1, s2);
}
```
```
s1 = hello, s2 = hello
```
* ヒープデータのコピーには`clone`を使用
* コピーされた`s2`は、`s1`の所有権を持たないため`println!`可能

### スタックで保持されるデータ
```rust
fn main() {
    let x = 5;
    let y = x;
    
    println!("The Value y is: {}", y);
    
    // NOT error    
    println!("The Value x is: {}", x); 
} 
```
```
The Value y is: 5
The Value x is: 5
```
* `String`における例と矛盾しているように見えるが、整数のような既知のサイズを持つ型は**スタック上に保持される**
* なので、`y = x`のようにコピーするときは所有権の移動が発生しない
* 値がコピーが起こることを**コピーセマンティクス**と呼び、これが起きる型は`Copy`トレイトが実装されている。`u32`や`bool`, `f64`, `char`などが対象（[Rustドキュメント](https://doc.rust-lang.org/std/marker/trait.Copy.html#implementors)）。

### 所有権と関数
```rust
fn main() {
    let s = String::from("hello");  // sがスコープに入る
    takes_ownership(s);             // sが関数にムーブ
    
    // この時点でsは有効ではない
    // println!("The value of s is: {}", s);

    let x = 5;     // xがスコープに入る
    makes_copy(x); // xが関数にムーブされるがi32はCopy
    println!("The value of x is: {}", x);
} // xもsもスコープを抜ける。ただしsは既にムーブ済み 

fn takes_ownership(some_string: String) {
    println!("{}", some_string);
} // some_stringがdrop

fn makes_copy(some_integer: i32) {
    println!("{}", some_integer);
} // some_integerがdrop
```
```
hello
5
The value of x is: 5
```
* 関数に変数を渡すと、ムーブやコピーが発生する
* ムーブされる`String`は、その後に再使用することはできず、`Copy`される`i32`は、再使用が可能

### 戻り値とスコープ
```rust
fn main() {
    let s1 = gives_ownership();        
    println!("{}", s1);                 // hello

    let s2 = String::from("world");     // s2がスコープに入る
    println!("{}", s2);                 // world

    let s3 = takes_and_gives_back(s2);  // s2は関数に所有権がムーブし、戻り値がs3にムーブ
                                        
    // println!("{}", s2);              // s2はムーブしたためNG
    println!("{}", s3);                 // world

} // s1, s3がdrop, s2もスコープ抜けるがムーブ済み

fn gives_ownership() -> String {  
    let some_string = String::from("hello"); // some_stringがスコープに入る
    some_string                              // 呼び出し元関数にムーブされる
}

fn takes_and_gives_back(a_string: String) -> String { 
    a_string  // 呼び出し元関数にムーブされる
}
```
```
hello
world
world
```
* 全ての関数で所有権を取られ、それをまた返さないといけないのは大変
* 作業量が多いため、**参照**という仕組みが存在

## 4-2章：参照と借用
https://doc.rust-jp.rs/book-ja/ch04-02-references-and-borrowing.html
```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()
}
```
```
The length of 'hello' is 5.
```
* `&`（参照）を渡すことで、関数に所有権を移すこと無く参照できている
* `&s1`で参照する参照を生成しているが、所有している訳ではないので`drop`されない
* `s.len()`も同様に、`s`自体はスコープを外れるものの、所有権を持っている訳では無いので何も起こらない。なお、引数に参照を取ることを**借用**と呼ぶ

### 借りたら返す
```rust
fn main() {
    let s = String::from("hello");
    change(&s);
    println!("{}", s);
}

fn change(some_string: &String) {
    some_string.push_str(", world");
}
```
```
error[E0596]: cannot borrow immutable borrowed content `*some_string` as mutable
(エラー: 不変な借用をした中身`*some_string`を可変で借用できません)
 --> error.rs:8:5
  |
7 | fn change(some_string: &String) {
  |                        ------- use `&mut String` here to make mutable
8 |     some_string.push_str(", world");
  |     ^^^^^^^^^^^ cannot borrow as mutable
```
* 借用した文字列を変更するとどうなるか？エラーが発生する
* 要するに、借りたものは綺麗に返しましょう

### 可変な参照
```rust
fn main() {
    let mut s = String::from("hello");
    change(&mut s);
    println!("{}", s);
}

fn change(some_string: &mut String) {
    some_string.push_str(", world");
}
```
```
hello, world
```
* 借用を変更するとエラーが発生したものが修正された
* 違いは可変な参照である`&mut s`を生成し、`&mut String`で受けること

### 同時にはできない参照
```rust
fn main() {
    let mut s = String::from("hello");

    let r1 = &mut s;
    let r2 = &mut s;

    println!("{}, {}", r1, r2);
}
```
```
$ cargo run
   Compiling ownership v0.1.0 (file:///projects/ownership)
error[E0499]: cannot borrow `s` as mutable more than once at a time
(エラー: 一度に`s`を可変として2回以上借用することはできません)
```
* ある特定のデータに対しては、1つしか可変な参照は持てない
* コンパイラでデータの競合を防いでくれている

### 可変と不変の参照の組み合わせ
```rust
fn main() {
    let mut s = String::from("hello");
    
    let r1 = &s;
    let r2 = &s; 
    let r3 = &mut s; 
}
```
```
error[E0502]: cannot borrow `s` as mutable because it is also borrowed as
immutable
(エラー: `s`は不変で借用されているので、可変で借用できません)
```
* なぜか自身の環境ではエラーが発生しなかったが、不変な参照をしている間は、可変な参照 (`&mut s`) はできない
* 不変な参照している間に、値が変わることを防ぐため

### ダングリングポインタ
```rust
fn main() {
    let reference_to_nothing = dangle();
}

fn dangle() -> &String {
    let s = String::from("hello");
    &s // sと書くべき
}
```
```
error[E0106]: missing lifetime specifier
(エラー: ライフタイム指定子がありません)
```
* ダンリングポインタは、ポインタが不正なメモリを指している状態
* `dangle()`内で宣言した`s`は、スコープが終わるところで解放されるが、`&s`で参照を返そうとしていたため、コンパイラが止めてくれる

## 4.3章：スライス型
https://doc.rust-jp.rs/book-ja/ch04-03-slices.html
### 愚直に文字列の長さを数える
```rust
fn main() {
    let mut s = String::from("hello world");
    let word = first_word(&s); 

    println!("s: {}", s);
    println!("word: {}", word);

    s.clear(); 
    
    println!("s: {}", s);
    println!("word: {}", word);
}

fn first_word(s: &String) -> usize {
    let bytes = s.as_bytes();
    println!("bytes: {:?}", bytes);

    for (i, &item) in bytes.iter().enumerate() {
        if item == b' ' {
            return i;
        }
    }

    s.len()
}
```
```
bytes: [104, 101, 108, 108, 111, 32, 119, 111, 114, 108, 100]
s: hello world
word: 5
s: 
word: 5
```
* `iter`はコレクションの各要素を返し、`enumerate`は`iter`の結果をそのまま返して、タプルの一部として各要素を返す
* `i`は添字 (1, 2, 3, ...)、`&item`は各要素 (104, 101, 108, ...)
* `s.clear()`すると、関連付けられていない`word`は値は5のまま維持される

### 文字列スライス
```rust
fn main() {
    let s = String::from("hello world");

    println!("{}", &s[0..5]);
    println!("{}", &s[6..11]);
    println!("{}", &s[..]);
    println!("{}", &s[2..]);
    println!("{}", &s[0..s.len()]);
}
```
```
hello
world
hello world
llo world
hello world
```
* 形式は`[starting_index..ending_index]`
* 末尾の1字を取得したい場合は、`&s[s.len()-1..s.len()]`でも通るが、`&s.chars().last().unwrap()`と書けるよう

```rust
fn main() {
    let mut s = String::from("hello world");
    let word = first_word(&s); 

    println!("s: {}", &s);
    println!("word: {}", word);

    // Error
    // s.clear(); 
}

fn first_word(s: &String) -> &str {
    let bytes = s.as_bytes();
    println!("bytes: {:?}", bytes);

    for (i, &item) in bytes.iter().enumerate() {
        if item == b' ' {
            return &s[0..i];
        }
    }

    &s[..]
}
```
```
bytes: [104, 101, 108, 108, 111, 32, 119, 111, 114, 108, 100]
s: hello world
word: hello
```
* 文字列スライスを使って、指定した部分まで文字列を出力
* ただし、`s.clear()`を実行することはできない
    * ルール1：不変な参照は幾つあってもOK
    * ルール2：可変な参照は1つのみで、他の参照は許可されない
* `word`が`s`不変借用している中で、`clear()`を使った可変借用はできない

### 引数としての文字列スライス
```rust
fn main() {
    // 1. String
    let my_string = String::from("hello world");
    let word = first_word(&my_string[..]);
    println!("word: {}", word);

    // 2. &str - スライス記法で指定
    let my_string_literal = "hello world";
    let word = first_word(&my_string_literal[..]);
    println!("word: {}", word);

    // 3. &str - スライス記法なし
    let word = first_word(my_string_literal);
    println!("word: {}", word);
}

fn first_word(s: &str) -> &str {
    let bytes = s.as_bytes();
    println!("bytes: {:?}", bytes);

    for (i, &item) in bytes.iter().enumerate() {
        if item == b' ' {
            return &s[0..i];
        }
    }

    &s[..]
}
```
```
bytes: [104, 101, 108, 108, 111, 32, 119, 111, 114, 108, 100]
word: hello
bytes: [104, 101, 108, 108, 111, 32, 119, 111, 114, 108, 100]
word: hello
bytes: [104, 101, 108, 108, 111, 32, 119, 111, 114, 108, 100]
word: hello
```
* 復習として、`String`は変更可能で実態は`Vec<u8>`。一方、`&str`は**文字列スライス**と呼び、変更不可で実態は`&[u8]`。文字列リテラルで定義したもの（コメントの2番）は&strとなる
* 文字列リテラルはコメントの1番のように、全要素を指定して参照を渡すことができるが、3番のように、スライス記法なしでも渡すことが可能

### 参考にさせていただいたサイト
* [#1 Rustの所有権が分からない
](https://blog.toriwatari.work/LearnSlowlyRust/01/)
* [The Rust Programming Language 要約 3-8章
](https://www.swlab.cs.okayama-u.ac.jp/~nom/lect/rust/The-Rust-Programming-Language-Summary-Chap3-8.html)