LoginSignup
2
0

More than 5 years have passed since last update.

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

Last updated at Posted at 2018-07-16

まだ数当てゲーム。
よくわかってないのでもうすこし考えてみる。
結局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じゃないとダメっぽい。

core::intrinsically::type_name

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

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

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

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

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

#![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));

}

実行するとこうなる。

[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以外が消えるのか。

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

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

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にとっとと変えておく手もあるか。
と思ってやってみたのがこれ。

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を保持するのであればネストしているのは使いづらそう。

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

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

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);
}
        .map_err(|e|panic!(e.description().to_string()))

を消せばエラーは無視。
入れとけばエラーでパニックする。
なんんかうまくいってるっぽい。

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

2
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
0