Rustで標準入力から複数行を入力するための方法

今回はRustで標準入力で複数行を入力しようと試行錯誤した時のことを備忘として書き残します。

Rustで標準入力しようと思った時によく出てくるのは以下のようなものです

fn main() {
    let mut buf = String::new();
    let stdin = std::io::stdin();
    stdin.read_line(&mut buf).unwrap();
    println!("{}", buf.trim());
}

ここで使われてるreadline()なんですが、読めるのが1行だけで、複数行の標準入力ができないんですよね

CLIツール作ってると、複数行の標準入力も対応したいなぁと思って試行錯誤をしました。

まず作ったのがこちら

use std::io::Read;
fn main() {
    let mut buf = String::new();
    let stdin = std::io::stdin();
    let mut handle = stdin.lock();
    handle.read_to_string(&mut buf).unwrap();
    for line in buf.lines() {
        println!("{}", line.trim());
    }
}

read_to_string()で一気に読み込んでしまうというものです。これで複数行の標準入力も取り込めます

。。。と思ったのですが、色々試してみると、標準入力でたくさん(といっても数行から十数行)書くと下記のエラーが出てpanicを起こします。

thread 'main' panicked at 'called `Result::unwrap()` on an `Err` value: Error { kind: InvalidInput, message: "Windows stdin in console mode does not support a buffer too small to guarantee holding one arbitrary UTF-8 character (4 bytes)" }', src\main.rs:6:37
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
error: process didn't exit successfully: `target\debug\rust.exe` (exit code: 101)

どうもバッファが足りなそうなので解決策を調べると、下記のように容量を増やしてやると、より多くの標準入力を読み込めるようになります。

use std::io::Read;
fn main() {
    let mut buf = String::new();
    buf.reserve(1000); // 追加した所。数値は適当
    let stdin = std::io::stdin();
    let mut handle = stdin.lock();
    handle.read_to_string(&mut buf).unwrap();
    for line in buf.lines() {
        println!("{}", line.trim());
    }
}

しかし、数値を決め込んでるのはナニだなぁと思い、他の書き方を探していたところ、ありました!!

use std::io::BufRead;
fn main() {
    let mut temp: Vec<String> = Vec::new();
    let stdin = std::io::stdin();
    for line in stdin.lock().lines() {
        temp.push(line.unwrap().trim().to_string());
    }
    for elem in temp {
        println!("{}", elem);
    }
}

lines()というのを使えば複数行読み込めるんですね!こっちの方が良さそう、ということで複数行の標準入力を読めるようにする記述ではこれを使ってます。