https://doc.rust-lang.org/book/ch02-00-guessing-game-tutorial.html
引き続き同じリポジトリ内で進めていく。
use std::io;
fn main() {
println!("guess the number!");
println!("Please input your guess.");
let mut guess = String::new();
io::stdin()
.read_line(&mut guess)
.expect("Failed to read line");
println!("You guessed: {}", guess);
}
use std::io;
ユーザの入出力を行う io ライブラリが提供されている。
std (標準ライブラリ) に含まれているので use std::io; でスコープに入れる。
fn main() {}
fn syntax は関数宣言、他の言語のように () で引数を受けることができる。
let hours = 12; // immutable
let mut age = 24; // mutable
let statement で変数を宣言する。
基本は immutable で mut を付けると mutable になる。
let mut guess = String::new();
上記コードにおける :: syntax は new が String 型の関連関数 (associated function) であることを示す。
String::new() で新しい空の文字列を生成する。
io::stdin()
.read_line(&mut guess)
io モジュールの stdin 関数でユーザ入力を処理できる。
& は引数が参照であることを示す。参照を用いることで同じデータを何度もメモリにコピーせずに済む。
immutable ならば &guess 、mutable ならば &mut guess と書く。
.expect("Failed to read line");
前述の read_line() で入力を受けると同時に値 (io::Result) を返す。
標準ライブラリには、汎用の Result や io::Result などが存在する。
これらの Result 型は enum で、列挙子は Ok と Err の 2 つ。
例えば read_line メソッドが失敗したとき io::Result インスタンスが Err を返すので、
expect メソッドに渡されている引数のメッセージ (msg) を表示する。
println!("You guessed: {}", guess);
{} はプレースホルダーで、フォーマット文字列内に複数使うこともできる。
上記コードでは guess の値がプレースホルダーに設定されて表示する。
let i = 1729;
let j = 628;
println!("i = {}, j = {}", i, j);
実行すると i = 1729, j = 628 と出力する。
Cargo.toml の [dependencies] 内に rand クレートを追加する。
[dependencies]
rand = "0.8.5"
追加後は cargo build コマンドでビルドする。
$ cargo build
Compiling libc v0.2.153
Compiling cfg-if v1.0.0
Compiling ppv-lite86 v0.2.17
Compiling getrandom v0.2.12
Compiling rand_core v0.6.4
Compiling rand_chacha v0.3.1
Compiling rand v0.8.5
Compiling learning_rust v0.1.0 (/home/oshiroman/projects/learning_rust)
Finished dev [unoptimized + debuginfo] target(s) in 1.07s
rand クレートのように外部依存を持つと、Cargo はそれらの依存関係をたどって、
最新のバージョンをレジストリ ( https://crates.io/ )から取得する。
コードから同じ生成物をリビルドするための仕組みを提供している。
Cargo.lock ファイルにはすべての依存関係のバージョンが記載されており、これによって再現性を保つ。
クレートをアップグレードしたい場合は cargo update コマンドを実行する。
ただしマイナーバージョンが変わるリリースは対象外となるので、
マイナーバージョン以上の変更を入れたい場合は Cargo.toml ファイルを編集する必要がある。
use rand::Rng;
let secret_number = rand::thread_rng().gen_range(1..=100);
Rng trait をスコープに入れて、乱数生成を行えるようにする。
今回は 1 から 100 までの整数を生成したいので 1..=100 または 1..101 と指定する。
use std::cmp::Ordering;
match guess.cmp(&secret_number) {
Ordering::Less => println!("Too small.."),
Ordering::Greater => println!("Too big..."),
Ordering::Equal => println!("YOU WIN!!!"),
}
std::cmp::Ordering 型を用いて比較を行う。
Ordering は Less / Greater / Equal を列挙子として持つ enum で、2 つの値を比較したときに得られる結果。
cmp メソッドで比較を行い、その結果に応じて match 式の評価を行う。
let guess: u32 = guess.trim().parse().expect("Please type a number!");
secret_number が i32 型に対して、入力された値は String 型であるため、
このままでは比較を行うことはできない。
trim メソッドで文字列 guess の空白 (先頭と末尾) を削除し、
parse メソッドで文字列を数値へ変換する。u32 型は符号なし 32 ビット整数を表す。
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!!!");
break;
}
}
}
loop と break でループとそれを抜ける処理を書く。
正解したときにループを抜けたいので Ordering::Equal が Ok のときに break を実行する。
let guess: u32 = match guess.trim().parse() {
Ok(num) => num,
Err(_) => continue,
};
expect でクラッシュさせるようにしていた部分を match 式を用いてエラー処理へと書き換える。
数値へ変換できない値を入力した場合は Err が評価されて continue が実行される。
use rand::Rng;
use std::cmp::Ordering;
use std::io;
fn main() {
println!("guess the number!");
let secret_number = rand::thread_rng().gen_range(1..=100);
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 = match guess.trim().parse() {
Ok(num) => num,
Err(_) => continue,
};
println!("You guessed: {guess}");
match guess.cmp(&secret_number) {
Ordering::Less => println!("Too small.."),
Ordering::Greater => println!("Too big..."),
Ordering::Equal => {
println!("YOU WIN!!!");
break;
}
}
}
}