rustとscalaとkotilnの勉強 数当てゲーム(rust) 補足  

まだ数当てゲーム。
よくわかってないのでもうすこし考えてみる。
結局rustはこんな感じ。

```rust
extern crate rand;
use std::io;
use std::cmp::Ordering;
use rand::Rng;
struct Gen<F>{
    f:F
}

impl<R,F:FnMut()->R> Iterator for Gen<F>{
    type Item=R;
    fn next(&mut self)->Option<R> { Some((self.f)()) }
}

fn main(){
    let secret_number = rand::thread_rng().gen_range(1,101);
    println!("秘密の数字は次の通り:{}",secret_number);
    println!("数をあててごらん");
    println!("ほら、予想を入力してね");

    Gen{f:||{
                let mut guess = String::new();
                io::stdin().read_line(&mut guess)
                    .map(|_| guess)
                    .map(|s| s.trim().parse::<u32>())
            }
        }
        .flat_map(|r| r)
        .filter_map(|r| r.ok())
        .map(|u| match u.cmp(&secret_number){
                        Ordering::Less => {println!("ちいさすぎる") ; u },
                        Ordering::Greater => {println!("大き過ぎる") ; u },
                        Ordering::Equal => {println!("正解"); u }
                    })
            .filter(|u| u == &secret_number)
            .nth(0);
}
```

いまいち型が追えていない。
なら逐一型を出してみよう、と思ったんだけど、、、
nightlyじゃないとダメっぽい。

```rust
core::intrinsically::type_name
```

で型名が取れるみたいなんだけど、これがnightly。
困った。
docker hubのofficialはstableしかない（たぶん）
うーーん。
officialのしかつかいたくないしななあ。
しばらく迷った結果、諦めた。
nightlyを使うDockerfileを自作する。
・・・めんどい、と思ったんだけどよく考えたらofficialのDockerfileのRUST_VERSIONをnightlyにすればいいだけなのに気付いた。

```dockerfile
ENV RUSTUP_HOME=/usr/local/rustup \
    CARGO_HOME=/usr/local/cargo \
    PATH=/usr/local/cargo/bin:$PATH \
    RUST_VERSION=nightly
```

これだけのために、、、
しょうがないね。
結局Dockerfileはこんな感じ。
officialのをまるっとコピってRUST_VERSIONだけ変えている。

```dockerfile
FROM	buildpack-deps:stretch
MAINTAINER xxx <xxx.xxx@xxx.xx>

ENV RUSTUP_HOME=/usr/local/rustup \
    CARGO_HOME=/usr/local/cargo \
    PATH=/usr/local/cargo/bin:$PATH \
    RUST_VERSION=nightly

RUN set -eux; \
# this "case" statement is generated via "update.sh"
    dpkgArch="$(dpkg --print-architecture)"; \
      case "${dpkgArch##*-}" in \
          amd64) rustArch='x86_64-unknown-linux-gnu'; rustupSha256='4d382e77fd6760282912d2d9beec5e260ec919efd3cb9bdb64fe1207e84b9d91' ;; \
          armhf) rustArch='armv7-unknown-linux-gnueabihf'; rustupSha256='0e606932b97b6d2a2ad494068ca9ba15962b98038e5f997779e3df1c9aa60b19' ;; \
          arm64) rustArch='aarch64-unknown-linux-gnu'; rustupSha256='c665cbf04f1c12536245b2f01d42fdf9ea77def7e7d7a3e54c1ae55bcb4eb415' ;; \
          i386) rustArch='i686-unknown-linux-gnu'; rustupSha256='57b85f60702198431735b5f54b083956bc148449edc82147542521f75d5dbd13' ;; \
          *) echo >&2 "unsupported architecture: ${dpkgArch}"; exit 1 ;; \
      esac; \
      url="https://static.rust-lang.org/rustup/archive/1.12.0/${rustArch}/rustup-init"; \
      wget "$url"; \
      echo "${rustupSha256} *rustup-init" | sha256sum -c -; \
      chmod +x rustup-init; \
      ./rustup-init -y --no-modify-path --default-toolchain $RUST_VERSION; \
      rm rustup-init; \
      chmod -R a+w $RUSTUP_HOME $CARGO_HOME; \
      rustup --version; \
      cargo --version; \
      rustc --version;

RUN apt-get update
RUN apt-get install -y sudo
RUN apt-get install -y vim-nox
RUN apt-get install -y zsh
RUN apt-get install -y emacs-nox

RUN apt-get install -y locales
RUN localedef -f UTF-8 -i ja_JP ja_JP.UTF-8
ENV LANG ja_JP.UTF-8
ENV LC_ALL ja_JP.UTF-8
ENV LANGUAGE ja_JP:ja

RUN echo "xxx ALL=(ALL) NOPASSWD: ALL" >> /etc/sudoers.d/xxx

RUN groupadd -g 1000 wheel \
&& useradd  -g wheel -G sudo -m -s /bin/bash xxx \
&& echo 'xxx:xxx' | chpasswd \
&& echo 'root:xxx' | chpasswd

ENV USER xxx
USER xxx

COPY .emacs /home/xxx/
COPY .vimrc /home/xxx/
COPY .zshrc /home/xxx/

RUN mkdir -p /home/xxx/study/rust
RUN mkdir -p /home/xxx/.vim
RUN mkdir -p /home/xxx/.vim/syntax
COPY .filetype.vim /home/xxx/.vim
COPY rust.vim /home/xxx/.vim/syntax
```

とりあえずこれで型を追ってみる。

```rust
#![feature(core_intrinsics)]

extern crate core;
use std::io;
use core::intrinsics::type_name;

struct Gen<F>{
    f:F
}

impl<R,F:FnMut()->R> Iterator for Gen<F>{
    type Item=R;
    fn next(&mut self)->Option<R> { Some((self.f)()) }
}

fn get_type_name<T>(_:&T) -> &'static str{
    unsafe{
        type_name::<T>()
    }
}
fn main(){
    let d = Gen{f:||{
        let mut s = String::new();
        let a = io::stdin().read_line(&mut s);
        println!("**a:{}",get_type_name(&a));
        let b = a.map(|_| s);
        println!("**b:{}",get_type_name(&b));
        let c = b.map(|s| s.trim().parse::<u32>());
        println!("**c:{}",get_type_name(&c));
        c
    }};
    println!("**d:{}",get_type_name(&d));
    let e = d.flat_map(|r|{
            println!("**r:{}",get_type_name(&r));
            r
            });
    println!("**e:{}",get_type_name(&e));
    let mut f = e.filter_map(|r|{
           println!("**r2:{}",get_type_name(&r));
           r.ok()
           });
    println!("**f:{}",get_type_name(&f));
    let g = f.nth(0);
    println!("**g:{}",get_type_name(&g));

}
```

実行するとこうなる。

```zsh
[xxx/ ~/study/rust/projects/scratch/map_and_err/src/ #docker-rust#]% cargo run(git)-[master]
   Compiling rand_core v0.2.1
   Compiling libc v0.2.42                                                                                                                                 Compiling rand v0.5.4                                                                                                                                  Compiling map_and_err v0.1.0 (file:///home/xxx/study/rust/projects/scratch/map_and_err)                                                             Finished dev [unoptimized + debuginfo] target(s) in 8.12s                                                                                               Running `/home/xxx/study/rust/projects/scratch/map_and_err/target/debug/map_and_err`
**d:Gen<[closure@src/main.rs:22:19: 31:6]>
**e:std::iter::FlatMap<Gen<[closure@src/main.rs:22:19: 31:6]>, std::result::Result<std::result::Result<u32, std::num::ParseIntError>, std::io::Error>, [closure@src/main.rs:33:24: 36:14]>
**f:std::iter::FilterMap<std::iter::FlatMap<Gen<[closure@src/main.rs:22:19: 31:6]>, std::result::Result<std::result::Result<u32, std::num::ParseIntError>, std::io::Error>, [closure@src/main.rs:33:24: 36:14]>, [closure@src/main.rs:38:30: 41:13]>
3
**a:std::result::Result<usize, std::io::Error>
**b:std::result::Result<std::string::String, std::io::Error>
**c:std::result::Result<std::result::Result<u32, std::num::ParseIntError>, std::io::Error>
**r:std::result::Result<std::result::Result<u32, std::num::ParseIntError>, std::io::Error>
**r2:std::result::Result<u32, std::num::ParseIntError>
**g:std::option::Option<u32>
```

なるほど。
flat_mapでok以外が消えるのか。

```rust
std::result::Result<std::result::Result<u32, std::num::ParseIntError>, std::io::Error>
```

ということは上記からu32を取り出すならflatten2回でいける？？
nightlyならflattenも使えるし。
やってみる。

```rust
extern crate rand;
use std::io;
use std::cmp::Ordering;
use rand::Rng;
struct Gen<F>{
    f:F
}

impl<R,F:FnMut()->R> Iterator for Gen<F>{
    type Item=R;
    fn next(&mut self)->Option<R> { Some((self.f)()) }
}

fn main(){
    let secret_number = rand::thread_rng().gen_range(1,101);
    println!("秘密の数字は次の通り:{}",secret_number);
    println!("数をあててごらん");
    println!("ほら、予想を入力してね");

    Gen{f:||{
                let mut guess = String::new();
                io::stdin().read_line(&mut guess)
                    .map(|_| guess)
                    .map(|s| s.trim().parse::<u32>())
            }
        }
        .flatten()
        .flatten()
        .map(|u| match u.cmp(&secret_number){
                        Ordering::Less => {println!("ちいさすぎる") ; u },
                        Ordering::Greater => {println!("大き過ぎる") ; u },
                        Ordering::Equal => {println!("正解"); u }
                    })
            .filter(|u| u == &secret_number)
            .nth(0);
}
```

いけた。
しかしなんだ。
どうせ使わないResultをflattenするまで持っとくのもなんだ。
使わないからoptionにとっとと変えておく手もあるか。
と思ってやってみたのがこれ。

```rust
extern crate rand;
use std::io;
use std::cmp::Ordering;
use rand::Rng;
struct Gen<F>{
    f:F
}

impl<R,F:FnMut()->R> Iterator for Gen<F>{
    type Item=R;
    fn next(&mut self)->Option<R> { Some((self.f)()) }
}

fn main(){
    let secret_number = rand::thread_rng().gen_range(1,101);
    println!("秘密の数字は次の通り:{}",secret_number);
    println!("数をあててごらん");
    println!("ほら、予想を入力してね");

    Gen{f:||{
                let mut guess = String::new();
                io::stdin().read_line(&mut guess)
                    .map(|_| guess)
                    .ok()
                    .and_then(|s| s.trim().parse::<u32>().ok())
            }
        }
        .flatten()
        .filter(|u| match u.cmp(&secret_number){
                        Ordering::Less => {println!("ちいさすぎる") ; false },
                        Ordering::Greater => {println!("大き過ぎる") ; false },
                        Ordering::Equal => {println!("正解"); true }
                    })
        .nth(0);
}
```

うん。いける。
逆に、、、というかResultを保持するのであればネストしているのは使いづらそう。

```rust
std::result::Result<std::result::Result<u32, std::num::ParseIntError>, std::io::Error>
```

とはいえ、当たり前だけどstd::num::ParseIntoErrorとstd::io::Errorは別の型だから同じ型としては扱えない。
・・・てことはトレイトオブジェクトの出番？？？
で書いてみたのがこれ。

```rust
extern crate rand;
use std::io;
use std::cmp::Ordering;
use rand::Rng;

struct Gen<F>{
    f:F
}

impl<R,F:FnMut()->R> Iterator for Gen<F>{
    type Item=R;
    fn next(&mut self)->Option<R> { Some((self.f)()) }
}

fn main(){
    let secret_number = rand::thread_rng().gen_range(1,101);
    println!("秘密の数字は次の通り:{}",secret_number);
    println!("数をあててごらん");
    println!("ほら、予想を入力してね");

    Gen{f:||{
        let mut guess= String::new();
        io::stdin().read_line(&mut guess).map_err(|e|Box::new(e) as Box<std::error::Error>)
        .map(|_| guess)
        .and_then(|s| s.trim().parse::<u32>().map_err(|e|Box::new(e) as Box<std::error::Error>))
        .map_err(|e|panic!(e.description().to_string()))
    }}
    .flatten()
    .map(|u| match u.cmp(&secret_number){
            Ordering::Less => {println!("ちいさすぎる") ; u },
            Ordering::Greater => {println!("大き過ぎる") ; u },
            Ordering::Equal => {println!("正解"); u }
        })
    .filter(|u| u == &secret_number)
    .nth(0);
}
```

```rust
        .map_err(|e|panic!(e.description().to_string()))
```
を消せばエラーは無視。
入れとけばエラーでパニックする。
なんんかうまくいってるっぽい。

これ、どうするのがいいんだろね。
状況によるだろうけど。