Rustの勉強(その5)
英語がね、体調によって読める精度がかなり変わるんですよ。。。
というわけで前回の続き。
mao-instantlife.hatenablog.com
処理のループ
前回までの状態だと一回の試行でプログラムが終わってしまうので、正解するまで帰れま10にします。
とりあえず無限ループ
とりあえずループさせたいときは、処理対象を loop
で囲んでしまえばいいようです。
loop { println!("Please input your guess."); let mut guess = String::new(); io::stdin().read_line(&mut guess) .expect("failed to read line"); let guess: u32 = guess.trim().parse() .expect("Please type a number!"); println!("You guessed: {}", guess); match guess.cmp(&secret_number) { Ordering::Less => println!("Too small!"), Ordering::Greater => println!("Too big!"), Ordering::Equal => println!("You win!"), } }
もちろん無限ループです。上記の状態で動かした場合は、数値以外入力して panic!
起こして止めようぜ、とのこと。雑でいいですね。
勝利条件のハンドリング
勝利した時にループを抜けるようにします。パターンマッチの Ordering::Equal
の場合の処理を以下のように変更。
match guess.cmp(&secret_number) { Ordering::Less => println!("Too small!"), Ordering::Greater => println!("Too big!"), Ordering::Equal => { println!("You win!"); break; } }
これは他の言語でもよくある break
ですね。自分の知識とマッピングできる領域は安心します。
入力エラーのハンドリング
現状、入力が数値ではなく、パースできない時にはエラーでプログラムが落ちます。非数値の入力で止めたくないので、エラーハンドリングしてまた入力してもらうようにしましょう。
let guess: u32 = match guess.trim().parse() { Ok(num) => num, Err(_) => continue, };
parse
の戻り値は Enum
なので、パターンマッチでエラーハンドリング可能みたいですね。 Ok
の時の数値を返す、 Err
の場合は continue
で再度入力させるようにしています。
これでnumber guessing gameはできたぜ、とのこと。
食事する哲学者の問題
次のサンプルは、「食事する哲学者の問題」を解決するプログラムを作る、というもの。
デッドロックを回避するマルチプロセスの古典的な問題っぽいですね。
型を定義する
まずは哲学者をモデリングしてみます。
struct Philosopher { name: String, } impl Philosopher { fn new(name: &str) -> Philosopher { Philosopher { name: name.to_string(), } } }
struct
が文字通り構造(フィールドの宣言?)の宣言で impl
が型の実装定義です。これって型定義に必ずインターフェイスが必要という理解でいいんですかね?このあたりは正直まだ違和感があります。
型の実装定義では、コンストラクタに相当する association function
である new
を定義しています。チュートリアルに「コンストラクタ」という言葉が出てこなかったのでRustではコンストラクタと言ってないのかもしれません。
引数と戻り値を指定する関数の定義
関数の定義を見てみます。
fn new(name: &str) -> Philosopher
関数名の後に引数リスト、その後に ->
で戻り値の型 *1 を指定するようです。割と馴染みのある表記なので安心。
String
と &str
?
Philosopher
型のフィールドにはString型を使っています。データの参照を使うより型を使ったほうが扱いやすいからという理由が書かれていましたが、メソッドが用意されていたり他のメソッドとのハンドリングがしやすいとかそんな理由でしょう。
それよりもわかりづらいのは new
の引数を &str
で受けていること。まだ全く理解できていないのですが、Javaの int
と Integer
とかと同じようにリテラルとそれをラップする型があると考えればいいのかな?上記コードを見る限り、そのまま文字列リテラルを定義すると &str
になるっぽいです。
new
の中で使っている to_string
メソッドは、文字列のコピーを作成して新しいString
インスタンスを作っています。
ちょっとキリ悪いけど
以下次号。