100 Exercises To Learn Rust に挑戦 🏃 🦀【0/37】 準備

こんにちは！株式会社ゆめみ 24卒のnamniumと申します！サーバーサイドエンジニア3ヶ月目で、先輩から色々と学ばせていただいております :bow:

ゆめみでは社内勉強会が活発です！私もRust勉強会に参加させてもらい、 [rustlings](https://github.com/rust-lang/rustlings) に取り組んだりしていました。

そんな折、X (旧Twitter) でrustlingsに似た新しいチュートリアルサイトの存在を知りました！

https://x.com/helloyuki_/status/1791642576891809858

https://rust-exercises.com/

rustlingsはRust至高の公式ドキュメント[The Rust Programming Language](https://doc.rust-lang.org/stable/book/) (通称TRPL) に従った内容だったのですが、[100-exercises](https://rust-exercises.com/)は[トレイト](https://rust-exercises.com/04_traits/00_intro)や[非同期処理](https://rust-exercises.com/08_futures/00_intro)等についてTRPLより深く踏み込んだ内容になっており、やりがいがありそうです！

Rust力を盤石にするため、[Qiita Engineer Fest 2024](https://qiita.com/official-campaigns/engineer-festa/2024)の力を借りてこの問題集に取り組んでみたいと思います！

# 2024/08/07 追記 (やっと)完走しました！

というわけで、全記事一覧になります！

- [【0】 準備](https://qiita.com/namn1125/items/bd1b4cd028874189a3c1)
- [【1】 構文・整数・変数](https://qiita.com/namn1125/items/c776768baec89b8a0438)
- [【2】 if・パニック・演習](https://qiita.com/namn1125/items/13870965e8273bc87bce)
- [【3】 可変・ループ・オーバーフロー](https://qiita.com/namn1125/items/4f57f8aede2f5201016f)
- [【4】 キャスト・構造体 (たまにUFCS)](https://qiita.com/namn1125/items/227ed5bbedbb775c5d27)
- [【5】 バリデーション・モジュールの公開範囲 ～ → カプセル化！～](https://qiita.com/namn1125/items/46721cceccbfa9ec3c7a)
- [【6】 カプセル化の続きと所有権とセッター ～そして不変参照と可変参照！～](https://qiita.com/namn1125/items/442de7798d49f777384c)
- [【7】 スタック・ヒープと参照のサイズ ～メモリの話～](https://qiita.com/namn1125/items/780d80e4340f0e34dbf6)
- [【8】 デストラクタ(変数の終わり)・トレイト ～終わりと始まり～](https://qiita.com/namn1125/items/7247edde3b6bd0b85b25)
- [【9】 Orphan rule (孤児ルール)・演算子オーバーロード・derive ～Empowerment 💪 ～](https://qiita.com/namn1125/items/e565713b423301a80c76)
- [【10】 トレイト境界・文字列・Derefトレイト ～トレイトのアレコレ～](https://qiita.com/namn1125/items/9060faee2965f23e0e3d)
- [【11】 Sized トレイト・From トレイト・関連型 ～おもしろトレイトと関連型～](https://qiita.com/namn1125/items/b68990712d379a3d6a49)
- [【12】 Clone・Copy・Dropトレイト ～覚えるべき主要トレイトたち～](https://qiita.com/namn1125/items/c6f34945f331c7229746)
- [【13】 トレイトまとめ・列挙型・match式 ～最強のトレイトの次は、最強の列挙型～](https://qiita.com/namn1125/items/6b2cc31d6a47f9ffaff6)
- [【14】 フィールド付き列挙型とOption型 ～チョクワガタ～](https://qiita.com/namn1125/items/6fe69d1cab6c7936c698)
- [【15】 Result型 ～Rust流エラーハンドリング術～](https://qiita.com/namn1125/items/698aafaf22ec4bfd1bde)
- [【16】 Errorトレイトと外部クレート ～依存はCargo.tomlに全部お任せ！～](https://qiita.com/namn1125/items/9dae7b728fa0668e4102)
- [【17】 thiserror・TryFrom ～トレイトもResultも自由自在！～](https://qiita.com/namn1125/items/d67006a29b7ff5d6148c)
- [【18】 Errorのネスト・慣例的な書き方 ～Rustらしさの目醒め～](https://qiita.com/namn1125/items/705829027661a38e4a4f)
- [【19】 配列・動的配列 ～スタックが使われる配列と、ヒープに保存できる動的配列～](https://qiita.com/namn1125/items/9c49fd4c08f3e61896c7)
- [【20】 動的配列のリサイズ・イテレータ ～またまたトレイト登場！～](https://qiita.com/namn1125/items/6e4dede789c6de97f396)
- [【21】 イテレータ・ライフタイム ～ライフタイム注釈ようやく登場！～](https://qiita.com/namn1125/items/9a1224abf733f29a980a)
- [【22】 コンビネータ・RPIT ～ :dragon: 「 `Iterator` トレイトを実装してるやつ」～](https://qiita.com/namn1125/items/27fe20f2d60803c94357)
- [【23】 `impl Trait` ・スライス ～配列の欠片～](https://qiita.com/namn1125/items/7601d0268293ce7fcf28)
- [【24】 可変スライス・下書き構造体 ～構造体で状態表現～](https://qiita.com/namn1125/items/a9acc7dc2ca7c4c55cc3)
- [【25】 インデックス・可変インデックス ～インデックスもトレイト！～](https://qiita.com/namn1125/items/bd43375362af10ea8b42)
- [【26】 HashMap・順序・BTreeMap ～Rustの辞書型～](https://qiita.com/namn1125/items/a2806cded12fa719a1cb)
- [【27】 スレッド・'staticライフタイム ～並列処理に見るRustの恩恵～](https://qiita.com/namn1125/items/5a4a09172834063268b1)
- [【28】 リーク・スコープ付きスレッド ～ライフタイムに技あり！～](https://qiita.com/namn1125/items/34a0aacd4d40f9234aef)
- [【29】 チャネル・参照の内部可変性 ～Rustの虎の子、mpscと `Rc<RefCell<T>>`～](https://qiita.com/namn1125/items/861e72dbb4b837508948)
- [【30】 双方向通信・リファクタリング ～返信用封筒を入れよう！～](https://qiita.com/namn1125/items/46f03de967d0de46737e)
- [【31】 上限付きチャネル・PATCH機能 ～パンクしないように制御！～](https://qiita.com/namn1125/items/d7ae8a205ee969339401)
- [【32】 `Send`・排他的ロック(`Mutex`)・非対称排他的ロック(`RwLock`) ～真打 `Arc<Mutex<T>>` 登場～](https://qiita.com/namn1125/items/eee890dc8672e975e70c)
- [【33】 チャネルなしで実装・Syncの話 ～考察回です～](https://qiita.com/namn1125/items/cc8bee3871b727e564e3)
- [【34】 `async fn`・非同期タスク生成 ～Rustの非同期入門～](https://qiita.com/namn1125/items/9c32b730a283ad76c891)
- [【35】 非同期ランタイム・Futureトレイト ～非同期のお作法～](https://qiita.com/namn1125/items/c840d48f8f558613ec10)
- [【36】 ブロッキング・非同期用の実装・キャンセル ～ラストスパート！～](https://qiita.com/namn1125/items/39c139da3f1f26264353)
- [【37】 Axumでクラサバ！ ～最終回～](https://qiita.com/namn1125/items/bae492f823fbe60e9974)
- [【おまけ1】 Rustで勘違いしていたこと3選 🏄🌴 【100 Exercises To Learn Rust 🦀 完走記事 🏃】](https://qiita.com/namn1125/items/2a59f486cce30fd2b889)
- [【おまけ2】 【🙇 懺悔 🙇】Qiitanグッズ欲しさに1日に33記事投稿した話またはQiita CLIとcargo scriptを布教する的な何か](https://qiita.com/namn1125/items/8e552694b389c5b13b5e)

初回は、問題に取り組むための環境構築をメインに書きます！

# 環境構築

筆者は今回 `Ubuntu 24.10` 上で取り組むことにします！インストール方法は公式サイトから確認できます。

https://www.rust-lang.org/ja/tools/install

...といっても難しい部分はまったくなく、Rust本体のインストールは、管理者権限要らずのたった1行で行うことができます！

```bash:コマンド
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
```

```bash:出力
info: downloading installer

Welcome to Rust!

~~ 省略 ~~

Current installation options:


   default host triple: x86_64-unknown-linux-gnu
     default toolchain: stable (default)
               profile: default
  modify PATH variable: yes

1) Proceed with standard installation (default - just press enter)
2) Customize installation
3) Cancel installation
>
```

ここで`1`を選択します。

```
1) Proceed with standard installation (default - just press enter)
2) Customize installation
3) Cancel installation
>1

~~ 省略 ~~


  stable-x86_64-unknown-linux-gnu installed - rustc 1.78.0 (9b00956e5 2024-04-29)


Rust is installed now. Great!

To get started you may need to restart your current shell.
This would reload your PATH environment variable to include
Cargo's bin directory ($HOME/.cargo/bin).

To configure your current shell, you need to source
the corresponding env file under $HOME/.cargo.

This is usually done by running one of the following (note the leading DOT):
. "$HOME/.cargo/env"            # For sh/bash/zsh/ash/dash/pdksh
source "$HOME/.cargo/env.fish"  # For fish
```

今のターミナルにてそのまま `cargo` コマンド等を打ちたい場合、`~/.cargo/env` を読み込ませます。ついでにバージョンも確認

```bash:コマンド
. "$HOME/.cargo/env"
cargo --version
```

```bash:出力
cargo 1.78.0 (54d8815d0 2024-03-26)
```

今月来るらしい `1.80` には `cargo-script` 等面白い機能が色々あるみたいなんですけどね...とりあえず `1.78.0` を前提として進めていきます！

これで準備完了...と行きたいところですが、Rustのコンパイルには `gcc` 等のC言語コンパイル環境の力が必要で、まっさらな状態のUbuntuから始めると以下のようなエラーが出るかもしれません。

```bash:コマンドと出力
$ cargo run
   Compiling project v0.1.0 (/path/to/project)
error: linker `cc` not found
  |
  = note: No such file or directory (os error 2)

error: could not compile `project` (bin "project") due to 1 previous error
```

`apt` で `build-essential` パッケージを入れれば `gcc` 等もインストールされ、無事コンパイルできるようになります。

```bash:コマンド
sudo apt update
sudo apt install build-essential
```

また [reqwest](https://docs.rs/reqwest/latest/reqwest/) クレートを使用する場合に `libssl-dev` が必要となったり等、他にもRustプログラミングをする上で色々と入れておいたほうが良いパッケージはありますが、エクササイズで必要になった際に都度入れることとします。

## 100 Exercises の導入

[100-exercises-to-learn-rust](https://rust-exercises.com/) を導入していきます。gitでクローンして取ってくる方式のようです。

```bash:コマンド
git clone https://github.com/mainmatter/100-exercises-to-learn-rust.git
cd 100-exercises-to-learn-rust
git checkout -b my-solutions
```

これで `main` ブランチの内容が手元にダウンロードされます。進捗管理のため `my-solutions` ブランチにて管理することをおすすめされたので、そのようにしています。 `exercises` ディレクトリ以下に問題があります。

なお、 [`solutions` ブランチ](https://github.com/mainmatter/100-exercises-to-learn-rust/tree/solutions) に模範解答があるらしいのでわからなくなったらそちらを適宜見たいと思います。

## Workshop Runner のインストール

rustlingsに専用の確認ツールがあったように、100 Exercisesの方にもチェック用ツールがあるようです。 `cargo install` でインストールします。

```bash:コマンド
cargo install --locked workshop-runner
wr --help
```

```bash:出力
$ wr --help
A CLI to run test-driven Rust workshops

Usage: wr [OPTIONS] [COMMAND]

Commands:
  open  Open a specific exercise
  help  Print this message or the help of the given subcommand(s)

Options:
      --no-skip     ...
      --verbose     ...
      --keep-going  ...
  -h, --help        Print help
  -V, --version     Print version
```

進捗管理を行ってくれるコマンドらしいです。問題を解き終えたら打ちましょう。

## エディタについて

デファクトスタンダードはVSCode + [rust-analyzer](https://marketplace.visualstudio.com/items?itemName=rust-lang.rust-analyzer)のため、筆者もこの組み合わせで行います。rust-analyzerは導入後特に設定する必要もないので、詳細は省略します。

その他の選択肢としては有料ですが最近正式リリースされた[RustRover](https://www.jetbrains.com/ja-jp/rust/)が良さげです。というか気になってる... :eyes:

# [[01_intro/00_welcome](https://github.com/mainmatter/100-exercises-to-learn-rust/tree/main/exercises/01_intro/00_welcome/src/lib.rs)] 最初の1問をやってみる

ここまでで無事環境構築が完了したので、いよいよ問題に取り組んでみたいと思います。`wr` コマンドを打ち`y`を選ぶと最初の問題に移ります。

```bash:コマンドと出力
$ wr
 

Running tests...

        Eternity lies ahead of us, and behind. Your path is not yet finished. 🍂

Do you want to open the next exercise, (01) intro - (00) welcome? [y/n] y


        Ahead of you lies (01) intro - (00) welcome

        Open "exercises/01_intro/00_welcome" in your editor and get started!
        Run `wr` again to compile the exercise and execute its tests.
```

`exercises/01_intro/00_welcome/src/lib.rs` を開いてみます。コメントにて、以下のようなことが書かれています。

- `//` は単行コメント
- `TODO` や `todo!()` 、 `__` はエクササイズにて取り組んでほしい箇所の強調である
- コードのチェックは[Rust標準のテスト機構](https://doc.rust-jp.rs/book-ja/ch11-01-writing-tests.html)をそのまま用いている( `cargo test` コマンドで確認できるやつ)。なお、`wr` コマンドが代替して行ってくれる
    - テストは変更しないでね

では、早速最初の1問を片付けて次の問題に進みましょう！

```rust:lib.rs
fn greeting() -> &'static str {
    // TODO: fix me 👇
    "I'm ready to __!"
}

#[cfg(test)]
mod tests {
    use crate::greeting;

    #[test]
    fn test_welcome() {
        assert_eq!(greeting(), "I'm ready to learn Rust!");
    }
}
```

<details><summary>コメントあり</summary>

```rust:lib.rs
// This is a Rust file. It is a plain text file with a `.rs` extension.
//
// Like most modern programming languages, Rust supports comments. You're looking at one right now!
// Comments are ignored by the compiler; you can leverage them to annotate code with notes and
// explanations.
// There are various ways to write comments in Rust, each with its own purpose.
// For now we'll stick to the most common one: the line comment.
// Everything from `//` to the end of the line is considered a comment.

// Exercises will include `TODO`, `todo!()` or `__` markers to draw your attention to the lines
// where you need to write code.
// You'll need to replace these markers with your own code to complete the exercise.
// Sometimes it'll be enough to write a single line of code, other times you'll have to write
// longer sections.
//
// If you get stuck for more than 10 minutes on an exercise, grab a trainer! We're here to help!
// You can also find solutions to all exercises in the `solutions` git branch.
fn greeting() -> &'static str {
    // TODO: fix me 👇
    "I'm ready to __!"
}

// Your solutions will be automatically verified by a set of tests.
// You can run these tests directly by invoking the `cargo test` command in your terminal,
// from the root of this exercise's directory. That's what the `wr` command does for you
// under the hood.
//
// Rust lets you write tests alongside your code.
// The `#[cfg(test)]` attribute tells the compiler to only compile the code below when
// running tests (i.e. when you run `cargo test`).
// You'll learn more about attributes and testing later in the course.
// For now, just know that you need to look for the `#[cfg(test)]` attribute to find the tests
// that will be verifying the correctness of your solutions!
//
// ⚠️ **DO NOT MODIFY THE TESTS** ⚠️
// They are there to help you validate your solutions. You should only change the code that's being
// tested, not the tests themselves.
#[cfg(test)]
mod tests {
    use crate::greeting;

    #[test]
    fn test_welcome() {
        assert_eq!(greeting(), "I'm ready to learn Rust!");
    }
}
```
</details>

テストが通るように直せばクリアです。

## 解説

単に、文字列を書き換えれば良さそうです！

```diff_rust:lib.rs
fn greeting() -> &'static str {
    // TODO: fix me 👇
-    "I'm ready to __!"
+    "I'm ready to learn Rust!"
}
```

一応関連する細かい解説をしておくと、`assert_eq!`という2つの引数を受け取る関数みたいなやつ([マクロ](https://doc.rust-jp.rs/book-ja/ch19-06-macros.html))は、与えられた2引数が等しいかどうかを判定しています。

「文字列の比較」になるので、他言語話者的には警戒する場面かもしれませんが安心してください。多分後の回で紹介されると思いますが、Rustにおいて `==` での比較は [eq](https://doc.rust-lang.org/std/cmp/trait.PartialEq.html#tymethod.eq)メソッドにより行われ、文字列については直感通り「頭から文字を比較していって全て等しいかを確認する」処理になっております。ポインタが等しいかとか直感に反する比較はありません[^eq]。

[^eq]: サードパーティやユーザーが作成した型については[std::cmp::PartialEq](https://doc.rust-lang.org/std/cmp/trait.PartialEq.html)トレイトの実装方法次第になるため注意が必要です。

問題が解けたのでまたプロジェクトルートから `wr` コマンドを打って正しいことを確認します。

```
$ wr


Running tests...

        🚀 (01) intro - (00) welcome
        Eternity lies ahead of us, and behind. Your path is not yet finished. 🍂

Do you want to open the next exercise, (01) intro - (01) syntax? [y/n]　y

        Ahead of you lies (01) intro - (01) syntax

        Open "exercises/01_intro/01_syntax" in your editor and get started!
        Run `wr` again to compile the exercise and execute its tests.
```

大丈夫そうです！では次の問題に行ってみましょう！

次の記事: [【1】 構文・整数・変数](https://qiita.com/namn1125/items/c776768baec89b8a0438)