まだ数当てゲーム。
よくわかってないのでもうすこし考えてみる。
結局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::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()))
を消せばエラーは無視。
入れとけばエラーでパニックする。
なんんかうまくいってるっぽい。
これ、どうするのがいいんだろね。
状況によるだろうけど。