Rustlings をやってみた: セットアップから variables 終了まで
業務委託で Rust を書くことになったので爆速キャッチアップを試みる.
ちなみに,本記事執筆開始時点で筆者の Rust 経験値は 0 であることを申し添えておく.
事前情報
macOS で動かしています.
先行記事の紹介
Google でヒットしたものから:
インストール
に従ってコマンドラインインストール:
curl -L https://git.io/install-rustlings | bash
コンパイルにはそれなりに時間かかる.
インストール完了後の作業
バージョン確認
rustlings
コマンドが使えるようになっている:
rustlings -v
# => v4.6.0
インストール先ディレクトリの確認
デフォルトではホームディレクトリ直下:
ls ~/rustlings
# => CHANGELOG.md Cargo.lock LICENSE default_out.txt info.toml install.sh target
# => CONTRIBUTING.md Cargo.toml README.md exercises install.ps1 src tests
rustlings watch
まずやること: インストール先ディレクトリ直下でこれを実行すると,rustlings/exercises
以下の exercise に対してビルドプロセスが走る:
pwd
# => /Users/kentarosugimoto/rustlings
rustlings watch
⚠️ Compiling of exercises/variables/variables1.rs failed! Please try again. Here's the output:
error[E0425]: cannot find value `x` in this scope
--> exercises/variables/variables1.rs:12:5
|
12 | x = 5;
| ^ not found in this scope
error[E0425]: cannot find value `x` in this scope
--> exercises/variables/variables1.rs:13:36
|
13 | println!("x has the value {}", x);
| ^ not found in this scope
error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0425`.
Welcome to watch mode! You can type 'help' to get an overview of the commands you can use here.
exercises/variables/variables1.rs
のビルドに失敗したことが分かる.
実際,variables
は https://github.com/rust-lang/rustlings/blob/main/exercises/README.md にもあるように初手の exercise トピックである.
というわけで,早速ビルドエラーを解消しにかかる.
variables1.rs
Debugging まずは variables1.rs
の内容を覗き見:
# bat: https://github.com/sharkdp/bat
bat ./exercises/variables/variables1.rs
// variables1.rs
// Make me compile! Execute the command `rustlings hint variables1` if you want a hint :)
// About this `I AM NOT DONE` thing:
// We sometimes encourage you to keep trying things on a given exercise,
// even after you already figured it out. If you got everything working and
// feel ready for the next exercise, remove the `I AM NOT DONE` comment below.
// I AM NOT DONE
fn main() {
x = 5;
println!("x has the value {}", x);
}
パッと見た感じ,関数 main
があるだけで,その内部スコープで宣言(?)されている x
という変数が正しくバインドされていないように感じる.
の前半に書いてあることをサッと拾うと
- 変数宣言には
let
キーワードが必要 - 宣言された変数はデフォルトでは immutable 扱い
- mutable にするためには
mut
キーワードを付加してlet mut
とする
- mutable にするためには
らしいので,必要そうな変更は 12
行目に let
を書き加えるだけ.
適当に vim で編集して再度 rustlings watch
を叩くと,下記のようなメッセージが出る:
✅ Successfully ran exercises/variables/variables1.rs!
🎉 🎉 The code is compiling! 🎉 🎉
Output:
====================
x has the value 5
====================
You can keep working on this exercise,
or jump into the next one by removing the `I AM NOT DONE` comment:
7 | // feel ready for the next exercise, remove the `I AM NOT DONE` comment below.
8 |
9 | // I AM NOT DONE
10 |
11 | fn main() {
Welcome to watch mode! You can type 'help' to get an overview of the commands you can use here.
テスト駆動開発(TDD)と似たようなリズムで演習問題を解けるのは良い:
- レッド:
rustlings watch
(修正前) - グリーン:
rustlings watch
(修正後) - リファクタリング:
I AM NOT DONE
の除去
というわけで,I AM NOT DONE
を除去し,再び rustlings watch
を実行すると,今度は variables1.rs
の実行に成功した旨に加えて,variables2.rs
のコンパイルに失敗した旨が出力される:
✅ Successfully ran exercises/variables/variables1.rs!
⚠️ Compiling of exercises/variables/variables2.rs failed! Please try again. Here's the output:
error[E0282]: type annotations needed
--> exercises/variables/variables2.rs:7:9
|
7 | let x;
| ^ consider giving `x` a type
error: aborting due to previous error
For more information about this error, try `rustc --explain E0282`.
Welcome to watch mode! You can type 'help' to get an overview of the commands you can use here.
variables2.rs
Debugging 今度は,型に関するエラー.
というわけで,はたまた内容を覗き見:
bat ./exercises/variables/variables2.rs
// variables2.rs
// Make me compile! Execute the command `rustlings hint variables2` if you want a hint :)
// I AM NOT DONE
fn main() {
let x;
if x == 10 {
println!("Ten!");
} else {
println!("Not ten!");
}
}
以下,https://doc.rust-lang.org/book/ch03-02-data-types.html などを読みつつ試行錯誤を行う.
とりあえず 10
前後の整数を表現可能な最小の型 u8
を嵌めてみる:
let x;
-> let x: u8;
これで rustlings watch
をやり直すと,新しいエラー:
✅ Successfully ran exercises/variables/variables1.rs!
⚠️ Compiling of exercises/variables/variables2.rs failed! Please try again. Here's the output:
error[E0381]: use of possibly-uninitialized variable: `x`
--> exercises/variables/variables2.rs:8:8
|
8 | if x == 10 {
| ^ use of possibly-uninitialized `x`
error: aborting due to previous error
For more information about this error, try `rustc --explain E0381`.
Welcome to watch mode! You can type 'help' to get an overview of the commands you can use here.
未初期化変数を参照するのは駄目,それはそう.では,後方に適当な代入文を付加したらどうなるか.
とりあえず代入文 x = 10;
を宣言文直後に差し込んでみて,再挑戦すると呆気なく通過:
✅ Successfully ran exercises/variables/variables1.rs!
✅ Successfully ran exercises/variables/variables2.rs!
🎉 🎉 The code is compiling! 🎉 🎉
Output:
====================
Ten!
====================
You can keep working on this exercise,
or jump into the next one by removing the `I AM NOT DONE` comment:
2 | // Make me compile! Execute the command `rustlings hint variables2` if you want a hint :)
3 |
4 | // I AM NOT DONE
5 |
6 | fn main() {
Welcome to watch mode! You can type 'help' to get an overview of the commands you can use here.
x == 10
以外の場合が気になり過ぎるので念の為見ておく:
✅ Successfully ran exercises/variables/variables1.rs!
✅ Successfully ran exercises/variables/variables2.rs!
🎉 🎉 The code is compiling! 🎉 🎉
Output:
====================
Not ten!
====================
You can keep working on this exercise,
or jump into the next one by removing the `I AM NOT DONE` comment:
2 | // Make me compile! Execute the command `rustlings hint variables2` if you want a hint :)
3 |
4 | // I AM NOT DONE
5 |
6 | fn main() {
Welcome to watch mode! You can type 'help' to get an overview of the commands you can use here.
特に問題はなさそう.次に行く.
variables3.rs
Debugging ✅ Successfully ran exercises/variables/variables1.rs!
✅ Successfully ran exercises/variables/variables2.rs!
⚠️ Compiling of exercises/variables/variables3.rs failed! Please try again. Here's the output:
error[E0384]: cannot assign twice to immutable variable `x`
--> exercises/variables/variables3.rs:9:5
|
7 | let x = 3;
| -
| |
| first assignment to `x`
| help: make this binding mutable: `mut x`
8 | println!("Number {}", x);
9 | x = 5; // don't change this line
| ^^^^^ cannot assign twice to immutable variable
error: aborting due to previous error
For more information about this error, try `rustc --explain E0384`.
Welcome to watch mode! You can type 'help' to get an overview of the commands you can use here.
これは,これまでの知識だけで最小限のコストで太刀打ちできる.
mut
キーワードを付けたら通った:
✅ Successfully ran exercises/variables/variables1.rs!
✅ Successfully ran exercises/variables/variables2.rs!
✅ Successfully ran exercises/variables/variables3.rs!
🎉 🎉 The code is compiling! 🎉 🎉
Output:
====================
Number 3
Number 5
====================
You can keep working on this exercise,
or jump into the next one by removing the `I AM NOT DONE` comment:
2 | // Make me compile! Execute the command `rustlings hint variables3` if you want a hint :)
3 |
4 | // I AM NOT DONE
5 |
6 | fn main() {
Welcome to watch mode! You can type 'help' to get an overview of the commands you can use here.
variables4.rs
Debugging 見たことのあるパターン,未初期化で怒られている:
✅ Successfully ran exercises/variables/variables1.rs!
✅ Successfully ran exercises/variables/variables2.rs!
✅ Successfully ran exercises/variables/variables3.rs!
⚠️ Compiling of exercises/variables/variables4.rs failed! Please try again. Here's the output:
error[E0381]: borrow of possibly-uninitialized variable: `x`
--> exercises/variables/variables4.rs:8:27
|
8 | println!("Number {}", x);
| ^ use of possibly-uninitialized `x`
error: aborting due to previous error
For more information about this error, try `rustc --explain E0381`.
Welcome to watch mode! You can type 'help' to get an overview of the commands you can use here.
今度は型注釈だけがあって代入がされていないパターン,さっき通過した中途半端なケースだ.
こういうときは,
- 宣言時の型注釈だけやって代入文だけ別に払い出す
- 型注釈するかしないかに関わらず宣言時に代入
のパターンがあると思うけど,綺麗に書きたい書き方を選ぶ余地があるのは良い.
とりあえず注釈を無くして適当な値を代入したら呆気なく成功:
✅ Successfully ran exercises/variables/variables1.rs!
✅ Successfully ran exercises/variables/variables2.rs!
✅ Successfully ran exercises/variables/variables3.rs!
✅ Successfully ran exercises/variables/variables4.rs!
🎉 🎉 The code is compiling! 🎉 🎉
Output:
====================
Number 5
====================
You can keep working on this exercise,
or jump into the next one by removing the `I AM NOT DONE` comment:
2 | // Make me compile! Execute the command `rustlings hint variables4` if you want a hint :)
3 |
4 | // I AM NOT DONE
5 |
6 | fn main() {
Welcome to watch mode! You can type 'help' to get an overview of the commands you can use here.
variables5.rs
Debugging
✅ Successfully ran exercises/variables/variables1.rs!
✅ Successfully ran exercises/variables/variables2.rs!
✅ Successfully ran exercises/variables/variables3.rs!
✅ Successfully ran exercises/variables/variables4.rs!
⚠️ Compiling of exercises/variables/variables5.rs failed! Please try again. Here's the output:
error[E0308]: mismatched types
--> exercises/variables/variables5.rs:9:14
|
9 | number = 3;
| ^ expected `&str`, found integer
error[E0369]: cannot add `{integer}` to `&str`
--> exercises/variables/variables5.rs:10:48
|
10 | println!("Number plus two is : {}", number + 2);
| ------ ^ - {integer}
| |
| &str
error: aborting due to 2 previous errors
Some errors have detailed explanations: E0308, E0369.
For more information about an error, try `rustc --explain E0308`.
Welcome to watch mode! You can type 'help' to get an overview of the commands you can use here.
見た感じ,型変換に関するエラーの模様.
// variables5.rs
// Make me compile! Execute the command `rustlings hint variables5` if you want a hint :)
// I AM NOT DONE
fn main() {
let number = "T-H-R-E-E"; // don't change this line
println!("Spell a Number : {}", number);
number = 3;
println!("Number plus two is : {}", number + 2);
}
創意工夫の余地がありそうだけど,ここは number
という変数を使い回す方針で行きたい.
というわけで,以下の変更を施す:
-
9
行目:number = 3;
->number = "3";
-
10
行目:println!("Number plus two is : {}", (number as u8) + 2);
一瞬できないかなと思ったものの,プリミティブ型同士の casting は一応サポートされているそう:
ちなみに,クォーテーションの規則は C と同じで
-
"<doubly-quoted>"
: 文字列 -
'<singly-quoted>'
: 文字
だそう,分かりやすくて良いね.
と思いきや,このアプローチも駄目:
✅ Successfully ran exercises/variables/variables1.rs!
✅ Successfully ran exercises/variables/variables2.rs!
✅ Successfully ran exercises/variables/variables3.rs!
✅ Successfully ran exercises/variables/variables4.rs!
⚠️ Compiling of exercises/variables/variables5.rs failed! Please try again. Here's the output:
error[E0606]: casting `&str` as `u8` is invalid
--> exercises/variables/variables5.rs:10:41
|
10 | println!("Number plus two is : {}", (number as u8) + 2);
| ^^^^^^^^^^^^^^
|
= help: cast through a raw pointer first
error: aborting due to previous error
For more information about this error, try `rustc --explain E0606`.
Welcome to watch mode! You can type 'help' to get an overview of the commands you can use here.
どうやら,整数型同士の変換以外はサポートされていないと思ったほうが良さげ.おとなしく別の変数を確保.
-
9
行目:number = "3";
->let number_i = 3;
-
10
行目:println!("Number plus two is : {}", number_i + 2);
これで通過した.ちなみに,変数名の緊急回避をスネークケースで行ったが,スタイルガイドにも「局所変数はスネークケース」以外のことは書かれていない:
まあいいや.
variables6.rs
Debugging ✅ Successfully ran exercises/variables/variables1.rs!
✅ Successfully ran exercises/variables/variables2.rs!
✅ Successfully ran exercises/variables/variables3.rs!
✅ Successfully ran exercises/variables/variables4.rs!
✅ Successfully ran exercises/variables/variables5.rs!
⚠️ Compiling of exercises/variables/variables6.rs failed! Please try again. Here's the output:
error: missing type for `const` item
--> exercises/variables/variables6.rs:6:7
|
6 | const NUMBER = 3;
| ^^^^^^ help: provide a type for the item: `NUMBER: i32`
error: aborting due to previous error
Welcome to watch mode! You can type 'help' to get an overview of the commands you can use here.
型推論が効きそうなケースで型注釈を要求されている.きっと const
キーワードで定数宣言がされているからに違いない.
を見ると,実際に型注釈が必要って書いてある.
でも型注釈が具体的に i32
で提案されているのは何故だろう...?
敢えて逆らって const NUMBER: i8 = 3;
としてみても問題なかった:
✅ Successfully ran exercises/variables/variables1.rs!
✅ Successfully ran exercises/variables/variables2.rs!
✅ Successfully ran exercises/variables/variables3.rs!
✅ Successfully ran exercises/variables/variables4.rs!
✅ Successfully ran exercises/variables/variables5.rs!
✅ Successfully ran exercises/variables/variables6.rs!
🎉 🎉 The code is compiling! 🎉 🎉
Output:
====================
Number 3
====================
You can keep working on this exercise,
or jump into the next one by removing the `I AM NOT DONE` comment:
2 | // Make me compile! Execute the command `rustlings hint variables6` if you want a hint :)
3 |
4 | // I AM NOT DONE
5 |
6 | const NUMBER: i8 = 3;
Welcome to watch mode! You can type 'help' to get an overview of the commands you can use here.
let
の場合もそうだけど,基本的に型注釈は左辺値で行う(当たり前):
let a: u8 = 4;
let b: i32 = -10;
というわけで,variables 編は無事に終わり.
プリミティブ型の種類に深入りすることなく終わったけど,本来プログラミング言語を新しく学ぶときってこのくらいのことだけ抑えておけば十分である.
というわけで,次回は functions 編.
次回予告
✅ Successfully ran exercises/variables/variables1.rs!
✅ Successfully ran exercises/variables/variables2.rs!
✅ Successfully ran exercises/variables/variables3.rs!
✅ Successfully ran exercises/variables/variables4.rs!
✅ Successfully ran exercises/variables/variables5.rs!
✅ Successfully ran exercises/variables/variables6.rs!
⚠️ Compiling of exercises/functions/functions1.rs failed! Please try again. Here's the output:
error[E0425]: cannot find function `call_me` in this scope
--> exercises/functions/functions1.rs:7:5
|
7 | call_me();
| ^^^^^^^ not found in this scope
error: aborting due to previous error
For more information about this error, try `rustc --explain E0425`.
Welcome to watch mode! You can type 'help' to get an overview of the commands you can use here.
スコープという概念が登場.
Discussion