今年の言語は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 クロージャ: 環境をキャプチャできる匿名関数

#### ジェネリック引数とFnトレイトを使用してクロージャを保存する

メモ化パターン または、 遅延評価パターン をやります

> 結果の値が必要な場合のみにその構造体はクロージャを実行し、その結果の値をキャッシュするので、残りのコードは、 結果を保存し、再利用する責任を負わなくて済むのです。このパターンは、メモ化(memoization)または、 遅延評価(lazy evaluation)として知っているかもしれません。

```rust
struct Cacher<T>
    where T: Fn(u32) -> u32 
{
      calculation: T,
      value: Option<u32>,
}


impl<T> Cacher<T>
    where T: Fn(u32) -> u32
{
    fn new(calculation: T) -> Cacher<T> {
        Cacher {
            calculation,
            value: None,
        }
    }
    
    fn value(&mut self, arg: u32) -> u32 {
        match self.value {
            Some(v) => v,
            None => {
                let v = (self.calculation)(arg);
                self.value = Some(v);
                v
            },
        }
    }
}
```

これはコーディング始めたばかりの頃だと、混乱してしまうやつだな


そして、クロージャを使うよ！

前回作っていた、関数をメモ化しました！

なんて便利なんだ！

この、コードはスニペット化して永久保存だな

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

// 前回のただの関数
//   let expensive_closure = |num:u32| -> u32 {
//         println!("calculating slowly...");
//         thread::sleep(Duration::from_secs(2));
//         intensity
//   };
   
   let mut expensive_result = Cacher::new(|num| {
        println!("calculating slowly...");
        thread::sleep(Duration::from_secs(2));
        num
   });
   
   
   if intensity < 25 {
       println!(
            "Today, do {} pushups!",
            expensive_result.value(intensity)
       );
       
       println!(
            "Next, do {} situps!",
            expensive_result.value(intensity)
       );
   } else {
       if random_number == 3 {
            println!("Take a break today! ");
       } else {
           println!(
                "Today, run for {} min",
                expensive_result.value(intensity)
            );
       }
   }
}
```


#### HashMapを使って、値を記録する

さぁ、初めての自分での実装.

コンパイラに助けてもらい何とかできました。
HashMap::get(&arg)等の参照渡しが慣れが必要ですね。。



```rust
impl<T> Cacher<T>
    where T: Fn(u32) -> u32
{
    fn new(calculation: T) -> Cacher<T> {
        Cacher {
            calculation,
            caches: HashMap::new()
        }
    }
    
    fn value(&mut self, arg: u32) -> u32 {
    
        match self.caches.get(&arg) {
            Some(v) => *v,
            None => {
                let v = (self.calculation)(arg);
                self.caches.insert(arg, v);
                v
            },
        }
    
    }
}

```

この章は、永久コピペですね！


イエス！