ここを見て0からrustを勉強し始めた
https://doc.rust-jp.rs/the-rust-programming-language-ja/1.6/book/README.html
予備知識として、ワイC言語10年くらいやってて、ここ5年くらいはphp、pythonあたりをメインに触っとる程度を前提に書くンゴ。
インストールまで完全に理解した
割愛。
アホでもできる。
3.1. 数当てゲーム 完全に理解した
https://doc.rust-jp.rs/the-rust-programming-language-ja/1.6/book/guessing-game.html
↑こいつを見ていく
まずはプロジェクト作成、余裕、完全に理解した。
$ cargo new guessing_game --bin
$ cd guessing_game
外部クレート(パッケージ)を使用するのでCargo.tomlに追記
dependencies に randを追記、バージョンを現時点最新のを指定してみた。
[dependencies]
rand="0.4.6"
まずはソースの完成形、完全に理解したわ
extern crate rand;
use std::io;
use std::cmp::Ordering;
use rand::Rng;
fn main() {
println!("Guess the number!");
let secret_number = rand::thread_rng().gen_range(1, 101);
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;
}
}
}
}
ソース、ちょい掘り下げて
①
外部クレートのrandを使えるようにする明示的宣言、Cの外部関数extern宣言と同じような意味合い。
externしなくても use rand::Rng があればコンパイル通る
extern crate rand;
②
!が付いてるのは関数じゃなくマクロ
println!("Please input your guess.");
③
let 変数束縛を作る。他言語と一番の違うのがこの辺、ここさえ乗り切ればrust完全に理解できると思う。
変数束縛とか言って、変数名に対して値を束縛する、とか言って所有権という概念が生まれる。
rustの言語の仕様として「Rustは与えられたリソースに対する束縛が 1つだけ あるということを保証する」
んで、変数束縛定義にmutを付けない場合、イミュータブルとか言って書き換え不可の定数になる。
gen_range(1, 101);は数値型を返され、secret_numberという変数に1~100の乱数が入る、
secret_numberがある数値を束縛する、secret_numberがこの乱数のリソースの所有権を持つ。
let secret_number = rand::thread_rng().gen_range(1, 101);
④
書き換え可能な変数作成は明示的にmutを付ける必要がある、ミュータブルとか言うやつ。
let mut guess = String::new(); の場合、guessという名前の変数にはString型のデータが入る。
String型にはポインタが含まれる、ので、この guess を別の変数に代入した場合、
guessとその別の変数はそれぞれ、同じアドレスを参照するポインタを持つことになるので、
同じリソースに対する束縛が同時に二つ存在することになる。
「Rustは与えられたリソースに対する束縛が 1つだけ あるということを保証する」ので、guess所有権が別の変数に渡され、
guess に対するアクセスができなくなる。
let aaa = guess;
println!(“{}”, guess); <= ここでコンパイルエラーになる。
let mut guess = String::new();
⑤
stdinのread_lineで入力された文字列をguessに入れる。この辺は直感的に理解できるが、
read_line(&mut guess) 見慣れない。read_lineの引数が&mut参照型なのでこうやって渡す必要がある。
ミュータブルの参照型で、参照先で変数を書き換え可能になる。
かつ、&を付けて参照で渡していると、所有権を渡すのではなく、借用することになる、スコープから外れると所有権が自動で元の束縛に戻る。
なので、read_line(&mut guess) でguessが束縛しているリソースをread_lineに借用、read_lineから抜けると自動的にguessに所有権が戻る。
上記④のようなコンパイルエラーが起きなくなる。
io::stdin().read_line(&mut guess)
.expect("Failed to read line");
長くなったので一旦区切り
続く。