saba1024のブログ

どうでも良い思いついた事とかプログラミング関係のメモとか書いていきます。

Rustでcatコマンドを実装

Rustでcatコマンドを実装しました。
ちゃんと標準入力からでも引数で指定されたファイルからでも読み込めます。
ミソになるのが、stdioでもFileでもBufReadというトレイトを実装しているので、そのトレイトの型を受け取って共通の処理が実現出来る点です。

use std::io::BufReader;
use std::io::BufRead;
use std::io::Stdin;
use std::fs::File;
use std::env;

fn main() {
    println!("cat implimented by Rust");
    let args: Vec<String> = env::args().collect::<Vec<String>>();

    // 標準入力から読み込み
    if args.len() <= 1 {
        let stdin: Stdin = std::io::stdin();
        // Readトレイトを実装している構造体であればBufReader::newに渡せる。
        let mut buf_file = BufReader::new(stdin);
        do_cat(&mut buf_file);

    // 引数で指定されたファイル(1つ以上)
   } else {
        args[1..].iter().for_each(|file_name| {
            match File::open(file_name) {
                Ok(file) => {
                    // Readトレイトを実装している構造体であればBufReader::newに渡せる。
                    let mut buf_file = BufReader::new(file);
                    do_cat(&mut buf_file);
                }
                Err(e) => println!("{}: {}", file_name, e),
                }
        })
    }
}

fn do_cat(stream: &mut BufRead) -> () {
    let mut buffer = String::new();
    loop {
        match stream.read_line(&mut buffer) {
            Ok(0) => break, // EOF
            Ok(_) => {
                print!("{}", buffer);
                buffer.clear();
            }
            Err(e) => {
                println!("{}", e);
                break;
            }
        }
    }
}