「並行プログラミング入門」読みすすめ その1 - NF
「並行プログラミング入門」読みすすめ その2 - NF
3回目、並行プログラミングからちょっと逸れて入力を学ぶ(問題解く用)
本の内容全然関係ないので注意してください。コンパイラはここを使います。
Online Rust Compiler - online editor
超基本
取り合えず教科書通りに書いてみる。
use std::io; fn main() { let mut s = String::new(); io::stdin().read_line(&mut s).expect("Failed to read line"); println!("{}", s); }
入力用の文字列型変数をmutで宣言して、read_lineにで更に&mutを指定して受け取る。
expect()は、関数(今回はread_line)が返すResult型がErrの時にプログラムをクラッシュさせて、指定して文字列を表示する。エラー出さずにクラッシュさせる場合は代わりにunwrap()で良いし、Okしか受け取らない場合はok()で良いらしい。
閑話休題
Okしか受け取らないって、実際にErr返ってきたらどうなるの?って思ったので試してみた。
fn foo() -> Result<i32, String> { Err("Error".to_string()) } fn main() { foo().expect("Failed to read line"); println!("{}", "test"); }
まずexpect()の場合、上記コードを実行すると標準エラーに以下が出力される。
expect()呼び出し時点でクラッシュするので、最後の"test"は標準出力されない。
thread 'main' panicked at 'Failed to read line: "Error"', main.rs:5:11
次に、「foo().expect(…)」を「foo().ok()」として実行すると、"test"が標準出力された。
と言う事で、Errは単にもみ消して次に進むっぽい。
指定の型で受け取る
本題に戻って、入力をもう少し掘り下げ。
入力値を整数型で受け取りたい場合は、こんな感じ。
use std::io; fn main() { let mut s = String::new(); io::stdin().read_line(&mut s).expect("Failed to read line"); let i:i32 = s.trim().parse().ok().unwrap(); println!("{}", i); }
空白で区切られた複数の値を受け取って、配列ぽく格納(出力)する場合はこんな感じ。
use std::io; fn main() { let mut s = String::new(); io::stdin().read_line(&mut s).expect("Failed to read line"); let v:Vec<i32> = s.trim().split_whitespace().map(|e| e.parse().ok().unwrap()).collect(); for &item in v.iter() { print!("{}", item); } }
trim()して空白を取り除いて…と長い、長くない?簡潔に書くやり方がありそうだが、一旦置いておく。
実演
ここまでの話の練習として、ABC286のA問題を解いてみる。入力はこんな感じで与えられる。
N S1 S2 ⋮ SN
入力だけやってみよう、と思ったら早速間違えました。
use std::io; fn main() { let mut in_str = String::new(); io::stdin().read_line(&mut in_str).ok(); let N:i32 = in_str.trim().parse().ok().unwrap(); print!("{}", N); for i in 0..N { io::stdin().read_line(&mut in_str).ok(); print!("{}", in_str); } }
これにサンプル2を入力したら、意図せず以下のように出力された。
read_lineの仕様見たら「appending it to the specified buffer.」と書いてあって、append(追加)なのね。
44 2023 4 2023 Year 4 2023 Year New 4 2023 Year New Happy
あと、letで宣言したNを配列宣言の要素数に使おうとすると、constにして、というエラーになるんですが…
これは解決策が分からなかったので、今回は配列を使わないようにして、宿題にする。
気を取り直して、多分以下のコードで良さそう。
use std::io; fn main() { let mut in_int = String::new(); io::stdin().read_line(&mut in_int).ok(); let N:i32 = in_int.trim().parse().ok().unwrap(); let mut v:Vec<String> = vec!["".to_string(); 0]; for i in 0..N { let mut in_str = String::new(); io::stdin().read_line(&mut in_str).ok(); v.push(in_str.trim().parse().ok().unwrap()); } for item in v.iter().rev() { println!("{}", item); } }
ポイントというかハマった所とかはこの辺。
・上で挙げた非const変数を配列数に指定できない
・Vec初期化の書き方が冗長な気がするけどもう少し何とかならないか(Vec::new()で良さそう)
・Vec型の変数(上のv)自体はiteratorじゃないのでrev()が使えない(先にv.reverse()しとくでも良さそう)
おまけ:proconio
他の方のACコード見てると、proconioというのがあるのに気付いた。(名前が直接的ですごい)
普通に使えるらしい。以下、まとめてくれている方の記事。
[Rustで簡単標準入力]proconio使い方まとめ - Qiita
ーーー
という訳で超初歩やりました。
全然慣れないので、初期化とか代入とかちょっとした事をやりたくですぐ詰まる。
次回は本の内容に戻りたい