Rustコトハジメ

プログラミング言語Rustと競プロに関する情報をお届けします。

sliceパターンを活用してプロコンの入力を読み取る

ALDSを読んでいて、時々気になった問題については手を動かすことにしています。

プログラミングコンテスト攻略のためのアルゴリズムとデータ構造

プログラミングコンテスト攻略のためのアルゴリズムとデータ構造

ほとんどのプロコン問題では何かしらの配列を受け取る時に、長さが与えられることが多く、そういう場合はtanakhさんのマクロが使ってとてもシンプルに読み込めるのですが、

qiita.com

優先度キューの問題(ALDS1_9_C)の入力はそういうタイプではなく、endが出るまで続くというタイプのものです。

f:id:akiradeveloper529:20190307140726j:plain

実際にこういうタイプの入力が与えられることが多いとは思いませんが、出てきてしまった時に書けないと困ってしまうので、入力を読むコードを書いてみました。

方針としては、大抵の場合は、enumに落とせる感じの文字列が与えられると考えて、文字列をsplitしてsliceパターンでマッチングさせることにします。

use std::io::stdin;
use std::str::FromStr;

#[derive(Debug)]
enum Message {
    Insert(i32),
    Extract,
    End,
}
impl FromStr for Message {
    type Err = Box<std::error::Error>;
    fn from_str(s: &str) -> Result<Self, Self::Err> {
        let v: Vec<&str> = s.split_whitespace().collect::<Vec<&str>>();
        match &v[..] {
            ["end"] => Ok(Message::End),
            ["extract"] => Ok(Message::Extract),
            ["insert", n] => Ok(Message::Insert(n.parse::<i32>()?)),
            _ => panic!()
        }
    }
}
fn main() {
    let mut s = String::new();
    while stdin().read_line(&mut s).unwrap() > 0 {
        let msg = s.parse::<Message>();
        println!("{:?}", msg);
        s.clear(); // 毎回クリアする必要がある。read_lineは追記
    }
}

出力:

Ok(Insert(8))
Ok(Insert(2))
Ok(Extract)
Ok(Insert(10))
Ok(Extract)
Ok(Insert(11))
Ok(Extract)
Ok(Extract)
Ok(End)

今回は、文字列をsplitしてsliceパターンでマッチさせるという方針でやりましたが、Scalaだったら、unapplyを実装するという方法もありそうです。もしRustでもそういう方法があるなら、

match s.trim() {
    Message::Insert(n) => q.insert(n)
    ...
}

のような形で書けそうです。パターンマッチの挙動を追加するトレイトはあるんでしょうか。見つかったらまた報告します。