今年の言語はRust その２３


# 今年の言語はRust その２３


Rustを学びます


Rustの日本語ドキュメント 2nd Edition
https://doc.rust-jp.rs/book/second-edition/

オリジナル(英語)
https://doc.rust-lang.org/book/



#### 実行環境

```sh
$ cargo -V
cargo 1.33.0 (f099fe94b 2019-02-12)
$ rustup -V
rustup 1.17.0 (069c88ed6 2019-03-05)
$ rustc --version
rustc 1.33.0 (2aa4c46cf 2019-02-28)

$  cat /proc/version
Linux version 4.14.97-74.72.amzn1.x86_64 (mockbuild@gobi-build-64002) (gcc version 7.2.1 20170915 (Red Hat 7.2.1-2) (GCC)) #1 SMP Tue Feb 5 20:59:30 UTC 2019

$ uname -a
Linux ip-10-100-0-8 4.14.97-74.72.amzn1.x86_64 #1 SMP Tue Feb 5 20:59:30 UTC 2019 x86_64 x86_64 x86_64 GNU/Linux

$ cat /etc/\*release
NAME="Amazon Linux AMI"
VERSION="2018.03"
ID="amzn"
ID_LIKE="rhel fedora"
VERSION_ID="2018.03"
PRETTY_NAME="Amazon Linux AMI 2018.03"
ANSI_COLOR="0;33"
CPE_NAME="cpe:/o:amazon:linux:2018.03:ga"
HOME_URL="http://aws.amazon.com/amazon-linux-ami/"
Amazon Linux AMI release 2018.03

```


## 10. ジェネリック

### 10.3 ライフタイムで参照を検証する

まずはエラーを起こさせる

```rust
fn main() {
    
    {
        let r;
        
        {
            let x = 5;
            r = &x;
        }
        
        println!("r: {}", r);
    }
}

===
error[E0597]: `x` does not live long enough
  --> src/main.rs:9:13
   |
9  |             r = &x;
   |             ^^^^^^ borrowed value does not live long enough
10 |         }
   |         - `x` dropped here while still borrowed
11 |         
12 |         println!("r: {}", r);
   |                           - borrow later used here

```


これは, xがすでに__スコープを抜けている__ために、__借用できないよ__ と怒られている

だれが？？

それは __借用精査機(borrow checker)__ を使用しています。

__Borrow Checkeeeer__ !



#### 借用精査機

スコープを変えて、__ダングリング参照__ を回避させる.


```rust
fn main() {
    
    {
        let x = 5;
        
        let r = &x;
        
        println!("r: {}", r);
    }
    
}
```

※ そもそもi32への参照ってなんだ？ intへのポインタってこと? スタックへも参照できるのか。

__振り返る__

```rust

■ ムーブ

let x = 5;
let y = x;

この場合、コピーされる。
※ 整数は既知の固定サイズなので、両方スタックに積まれる。


■ ムーブ

let s1 = String::from("hello");
let s2 = s1;

この場合は、ムーブされる。
※ Stringは、ヒープ上の"hello"に対する、スライス(ポインタ、長さ、キャパ構造体)
※ スタックに積まれた2つのスライス(s1, s2)は、メモリの二重解放を避けるために、s1が解放される。


■ クローン

let s1 = String::from("hello");
let s2 = s1.clone();


```

そうだったね




```rust
fn main() {
    
    {
        let x = 5;
        
        let r = &x;
        
        println!("r: {}", r);
        println!("x: {}", x);
    }
    
        
    {
        let x = 5;
        
        let r = x;
        
        println!("r: {}", r);
        println!("x: {}", x);
    }
}
```

### 関数のジェネリックなライフタイム

長さを比較する関数を作って考えてみる.


二つの文字列スライスへの参照を受け取り、長さを比較して、 __長いほう__ のスライスを返したい。

しかし、以下のようにすると、ライフタイムに言及するエラーがおこる。

参照でもらったものを、参照で返す...

できそうだけど、Rustではできなさそう。


```rust
fn longest(x: &str, y: &str) -> &str {
    if x.len() > y.len() {
        x
    }else{
        y
    }
}

===
error[E0106]: missing lifetime specifier
 --> src/main.rs:1:33
  |
1 | fn longest(x: &str, y: &str) -> &str {
  |                                 ^ expected lifetime parameter
  |
  = help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from `x` or `y`

```

エラーとなる説明

>助言テキストが戻り値の型はジェネリックなライフタイム引数である必要があると明かしています。 というのも、返している参照がxかyを参照しているかコンパイラにはわからないからです。 この関数の本体のifブロックはxへの参照を返し、elseブロックはyへの参照を返すので、 実際、どちらか私たちにもわかりません！

???

>この関数を定義する際、この関数に渡される具体的な値がわからないので、ifケースか、elseケースが実行されるか、わからないのです。 また、渡される参照の具体的なライフタイムもわからないので、リスト10-18と10-19で、 返す参照が常に有効であるかを決定したようにスコープを見ることもできないのです。 借用精査機もこれを決定することはできません。xとyのライフタイムがどう戻り値のライフタイムと関係するかわからないからです。 このエラーを修正するには、借用精査機が解析を実行できるように、参照間の関係を定義するジェネリックなライフタイム引数を追加します。

???

これを回避するには

__ライフタイム注釈記法__ を学ぶ必要がある。

まだまだ、長そうなのでいったんここまで


次回は、ライフタイム注釈記法!!


イエス！