今年の言語は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

```



## 13. 関数型言語の機能: イテレータとクロージャ

### 13.1 クロージャ: 環境をキャプチャできる匿名関数

#### クロージャで動作の抽象化を行う

```rust

use std::thread;
use std::time::Duration;


fn simulated_expensive_calculation(intensity: u32) -> u32 {
    
    println!("calculating slowly...");
    
    thread::sleep(Duration::from_secs(2));
    
    intensity
}


fn generate_workout(intensity: u32, random_number: u32){
   
   if intensity < 25 {
       println!(
        "Today, do {} pushups!",
        simulated_expensive_calculation(intensity);
       );
       
       println!(
        "Next, do {} situps!",
        simulated_expensive_calculation()
       );
   } else {
       if random_number == 3 {
           println!("Take a break today! ");
       } else {
           println!(
            "Today, run for {} min",
            simulated_expensive_calculation(intensity)
            );
       }
   }
}


fn main() {

    
    let simulated_user_specified_value = 10;
    let simulated_random_number = 7;
    
    generate_workout(
        simulated_user_specified_value,
        simulated_random_number,
    );
}

```

> このコードは、ビジネスのほしいままに動くでしょうが、データサイエンスチームが、 simulated_expensive_calculation関数を呼び出す方法に何らかの変更を加える必要があると決定したとしましょう。 そのような変更が起きた時に更新を簡略化するため、simulated_expensive_calculation関数を1回だけ呼び出すように、 このコードをリファクタリングしたいです。また、その過程でその関数への呼び出しを増やすことなく無駄に2回、 この関数を現時点で呼んでいるところを切り捨てたくもあります。要するに、結果が必要なければ関数を呼び出したくなく、 それでも1回だけ呼び出したいのです。


ちょっとよくわからない

#### 関数でリファクタリング

```rust
fn generate_workout(intensity: u32, random_number: u32){


   let expensive_result = 
            simulated_expensive_calculation(intensity);
   
   if intensity < 25 {
       println!(
            "Today, do {} pushups!",
            expensive_result
       );
       
       println!(
            "Next, do {} situps!",
            expensive_result
       );
   } else {
       if random_number == 3 {
            println!("Take a break today! ");
       } else {
           println!(
                "Today, run for {} min",
                expensive_result
            );
       }
   }
}
```


> この変更によりsimulated_expensive_calculationの呼び出しが単一化され、 最初のifブロックが無駄に関数を2回呼んでいた問題を解決します。不幸なことに、これでは、 あらゆる場合にこの関数を呼び出し、その結果を待つことになり、結果値を全く使用しない内側のifブロックでもそうしてしまいます。

ちょっとよくわからない


#### クロージャでリファクタリングして、コードを保存する


```rust
use std::thread;
use std::time::Duration;


fn generate_workout(intensity: u32, random_number: u32){

   let expensive_closure = |num| {
        println!("calculating slowly...");
        thread::sleep(Duration::from_secs(2));
        num
   };
   
   
   if intensity < 25 {
       println!(
            "Today, do {} pushups!",
            expensive_closure(intensity)
       );
       
       println!(
            "Next, do {} situps!",
            expensive_closure(intensity)
       );
   } else {
       if random_number == 3 {
            println!("Take a break today! ");
       } else {
           println!(
                "Today, run for {} min",
                expensive_closure(intensity)
            );
       }
   }
}


fn main() {

    
    let simulated_user_specified_value = 10;
    let simulated_random_number = 7;
    
    generate_workout(
        simulated_user_specified_value,
        simulated_random_number,
    );
}
```

> 今では、重い計算はたった1箇所でのみ呼び出され、その結果が必要なコードを実行するだけになりました。
> ところが、リスト13-3の問題の一つを再浮上させてしまいました



#### クロージャの型推論と注釈

```rust
let expensive_closure = |num:u32| -> u32 {
    println!("calculating slowly...");
    thread::sleep(Duration::from_secs(2));
    intensity
};
```

クロージャの書き方一覧

```rust
// 関数定義
fn add_one_v1(x: u32) -> u32 { x + 1}

// クロージャ
let add_one_v2 = |x: u32| -> u32 { x+1 };
let add_one_v3 = |x| { x + 1 };
let add_one_v4 = |x| x + 1;
```

クロージャは、引数と戻り値に対して具体的な型が推論される

```rust
let example_closure = |x| x;

let s = example_closure(String::from("hello"));
let n = example_closure(5);

```

上のような場合は、引数の型が変わっている
そのため、二回目の呼び出し時にTypeエラーがでてしまうので注意してね




イエス！