https://doc.rust-lang.org/book/second-edition/
Apache License Version 2.0
2. Guessing Game
数あてゲームを作る.
bash
cargo new guessing_gaame --bin
で新しいプロジェクトを作成する.ランダムな整数を生成するのにrandクレートを使うので,Cargo.tomlにrandを追加する.クレートはrustコードのパッケージであって,randはlibraryクレートと言って,他のプログラムで利用されるコードが入っている.
Cargo.toml
[dependencies]
rand = "0.3.14"
main.rs
use std::io; // 標準ライブラリのioを名前空間に追加.
// std::io::stdin()をio::stdin()と省略できる.
use std::cmp::Ordering;
use rand::Rng;
fn main() { // Rustではfn <関数名>で関数を定義する.
// Cと同じくmainが最初に実行される.
println!("Guess the number!"); // 文字列をコンソールに書き出すマクロ.
// !は関数でなくマクロを読んでいることを表している.
// インデントは4スペースがいいらしいが色々と統一したいので2スペース
// ;でexpressionの終わりを明示する.
// Cなどの,行の終わりに;を打つ言語とはちょっと違うらしい(後述).
let secret_number = rand::thread_rng().gen_range(1, 101); // thread_rng()がランダムなジェネレーターをつくる
// .gen_range(1,101)で範囲内の値で生成するようにする
loop { // 中でbreakするまで繰り返す.カウンタを使わない分処理が早い
println!("Please input your guess");
let mut guess = String::new(); // 変数の宣言は'let'で行う. 'mut'によって変数guessを可変にする.
// let foo=bar;などとすると,fooにはbarが代入されて以後変更できない
// String::new()は長さが可変な文字列型Stringのassociated functionで,
// 新しい空の文字列を作成する.
io::stdin().read_line(&mut guess) // 後述(1)
.expect("Failed to read line");
let guess: u32 = match guess.trim().parse() { // 後述 (2)
Ok(num) => num,
Err(_) => continue,
};
println!("You guessed: {}", guess); // 変数を文字列に埋め込んで出力する方法はpythonと同じ
match guess.cmp(&secret_number) { // 後述 (3)
Ordering::Less => println!("Too small!"),
Ordering::Greater => println!("Too big!"),
Ordering::Equal => {
println!("You win!");
break;
}
}
}
}
(1)
io::stdin().read_line(&mut guess) // 後述(1)
.expect("Failed to read line");
io::stdin()は標準入出力のhandleのインスタンスを返す.そのインスタンスのメソッドread_lineが入力を読み取り,guessに文字列として代入する.代入先の変数は可変でなければならない.&はこの引数がreferenceであることを表していて,いちいち新しくメモリを割り当てさせない.referenceはChap.4で詳しく論じる.
一行目で行われた処理はguessに値を代入することだが,read_line()はio::Reuslt型の返り値を返す.Result型は’Ok’か’Err’の値しか取らない.’Ok’は処理が正常に行われたとき返され,’Err’はそうでないときに返される.Result型のexpectメソッドによって,実行時のインスタンスがErrであったときはexpectの引数である文字列を表示し,プログラムはクラッシュする.Resultのインスタンスにexpectをつけないとコンパイル時に警告される.
(2)
let guess: u32 = match guess.trim().parse() { // 後述 (2)
Ok(num) => num,
Err(_) => continue,
};
let <変数名> :<変数型>によって,型を指定して変数を定義できる.
新しい変数guessをu32型として定義して,もとあったguessを数値に変換した値を新しいguessに代入する.(このように,同じ名前の変数を定義して,もとあった変数を加工した値を代入することをshadowingという.)
trim()メソッドによって文字列の始まりと終わりにある空白を削除し,更にparse()によって改行記号があればそれを削除する.parse()が正常に機能したか否かをmatch expressionによって条件分岐し,正常な場合は新しいguessに,古いguessを数値として代入する.異常な場合はcontinueによって直ちに次にループを実行する.
Err()の’‘はcatchall記号で,エラーの詳細が何であっても,Errならこれに一致する.
match A { B => b, C => c, D => d, ...};
は, A がXに等しいときxを返したり実行したりする.
(3)
match guess.cmp(&secret_number) { // 後述 (3)
Ordering::Less => println!("Too small!"),
Ordering::Greater => println!("Too big!"),
Ordering::Equal => {
println!("You win!");
break;
}
cmpメソッドはもとのインスタンスと引数の大小比較を行い,std::cmp::Ordering型のインスタンス{Less,Greater,Equal}のどれかを返す.返されたインスタンスが何であるかによる条件分岐をmatch expressionで実現する.
0 件のコメント:
コメントを投稿