オンラインジャッジなどの問題では、「n 個の数字を読み込む」コードをしょっちゅう書く。Rust でこれを扱うとき、大体こんなかんじではないか。
(読み込む個数 n は問題で指定されているとする)
/* 標準入力を開いて */
let mut scan = std::io::stdin();
let mut line = String::new();
/* 読み込んで */
let _ = scan.read_line(&mut line);
/* 空白で分割してからベクタにまとめる */
let vec: Vec<&str> = line.split_whitespace().collect();
/* それぞれを変換 */
let n: i32 = vec[0].parse().unwrap_or(0);
let m: f32 = vec[1].parse().unwrap_or(0.0);
let k: u32 = vec[2].parse().unwrap_or(0);
split_whitespace() が半角スペースでも改行でも分割してくれるので、上のコードで
1
2.0
3
でも、
1 2.0 3
でも読み込むことができる。
ところで唐突だけど Common Lisp で書くならこんなコードになる。
(loop repeat 3 collect (read))
短い。read に読み込みと分割と変換を全部任せられるからだ。 文字列を読み込むのならばこのコードではだめで、もうすこし (プログラマが) 分担しなければならないが、読むのが数字だけとわかっていればこれで十分だ。
Common Lisp でこのようなコードを書くことに慣れていると、Rust のコードは長すぎてつらい。 開いて、read_line して、 split_whitespace して、parse して、という一連の流れに慣れればいい、というのはその通りなのだけど、もうちょっと短くしたい。 具体的にはこういうふうに書きたい。
let (n, m, k) = read_from_stdin(i32, f32, u32);
fn read_from_stdin<T, S, P>() -> (T, S, P)
where T: std::str::FromStr + Default,
S: std::str::FromStr + Default,
P: std::str::FromStr + Default {
let mut scan = std::io::stdin();
let mut line = String::new();
let _ = scan.read_line(&mut line);
let vec: Vec<&str> = line.split_whitespace().collect();
(vec[0].parse::<T>().unwrap_or(Default::default()),
vec[1].parse::<S>().unwrap_or(Default::default()),
vec[2].parse::<P>().unwrap_or(Default::default()))
}
これで、
let (n, m, k) = read_from_stdin::<i32, f32, u32>();
と読み込める。
これは 3 個読み込むのにしか使えない。 2 個のときは 2 個用の関数を別に書く必要がある。だるい。
マクロを使えば解決できるのかもしれないが、今のところ、 vec[0], vec[1], vec[2], ... を扱う方法がわからない。