
記事の概要
この記事では、システム開発言語のRustを使って、Dockerコンテナで動作するCLI(Comman Line Interface)アプリの開発環境の構築から開発、実行までの流れを紹介します。
この記事を参考に、RustやCLIアプリ開発のスタートの一助となれば幸いです。
今回の記事の対象者
この記事は次のような方に向けています:
- Rustの開発環境を構築してアプリ開発を始めたい方
- シンプルなCLIアプリでRustの実装イメージを掴みたい方
- Dockerコンテナを使ってサーバー(VPSやクラウド環境)を環境を統一したい方
はじめに
普段は、JavaやPython使ってWebアプリやバックエンドのWebAPIの開発を行っていますが、以前からポストC/C++と噂になっているRustを使ってみたくなりました。
Rustは、システムプログラミングに適したプログラミング言語で、Mozillaが開発しました。主な特徴は、安全性、速度、並行性に優れていることです。
Rustは主に以下の特徴があります。
- Rustは速くて安全なプログラムを作るのに適した言語である
- プログラムがうまく動かない原因(バグ)を防ぐための特別な仕組みがある
- 同時にいろんなことをやらせても、安全に動かすことができる
- Cargoを使うと、プロジェクトの管理やプログラムのビルドが簡単にできる
Rustは、以下のようなソフトウェア開発に適しています。
- オペレーティングシステムやデバイスドライバ
- 高パフォーマンスなWebサーバー
- ゲームエンジン
- 組み込みシステム
- ブロックチェーンや暗号通貨関連の技術
Rustについての詳細は、公式サイトをご覧下さい。また、学習用に豊富なドキュメントがあります。
目次
- CLI(Command Line Interface)アプリ概要
- ソフトウェア・ハードウェア
- Rust開発環境の構築
- カウントダウンアプリの開発
- アプリの実行
- コードの解説
- まとめ
CLI(Command Line Interface)アプリ概要
本記事では簡単なカウントダウンタイマーの機能を提供するCLIアプリを使ってRustの以下の基本機能を実装して学習します。
- 標準入力の取り扱い
- エラーハンドリング
- 時間操作
- シンプルなループと条件分岐
【筆者の一言】
CLI (Command Line Interface) とは、コンピュータやシステムとやり取りをするためのインターフェースの一つです。通常、コンピュータとやり取りするための方法として、グラフィカルユーザーインターフェース (GUI) を使用しますが、CLI では文字ベースのコマンドを直接入力して操作します。
CLIを使うと、複雑な操作や一括処理を効率的に行うことができます。GUIではマウス操作が多くなることが多いですが、CLIではコマンドを打つだけで複数の作業を一度に行えるため、慣れるととても便利です。
カウントダウンタイマーアプリ
ユーザーが指定した時間(秒数)から0になるまでカウントダウンする簡単なタイマーを作成します。
- ユーザーが秒数を入力。
- 入力検証を行い、有効な値が得られたらカウントダウンを開始。
- 1秒ごとに残り時間を表示しながら、0秒になるまでループ。
- カウントダウン終了後、完了メッセージを表示。
機能概要を以下に示します。
1. ユーザーインターフェース
- コマンドライン入力: ユーザーがカウントダウンする時間(秒数)をコマンドラインで入力します。
- 例: 「Please enter the countdown time in seconds: 」と表示し、ユーザーに入力を促す。
- 入力検証: 入力された値が正の整数であるかを確認し、不適切な入力があれば再度入力を促すメッセージを表示します。
- 例: 「Invalid input. Please enter a positive integer.」
2. カウントダウン機能
- タイマー開始: ユーザーが有効な秒数を入力すると、カウントダウンが開始されます。
- 時間表示: 現在の残り秒数を1秒ごとに表示します。
- 例: 残り時間が「10秒」であれば、「Time left: 10 seconds」と表示し、次に「Time left: 9 seconds」と更新されます。
- 1秒ごとに更新: カウントダウンはリアルタイムで1秒ごとに画面を更新し、残り時間を減少させます。
3. 終了処理
- カウントダウン完了: 残り時間が0秒になると、カウントダウンが終了します。
- 完了メッセージ: カウントダウン終了後に、画面に「Time’s up!」または「Countdown finished!」と表示します。
ソフトウェア・ハードウェア
必要なツール、ライブラリ、端末は以下の通りです。
開発ツール
以下、開発ツールとその公式サイトの一覧です。導入しておくと開発作業が楽になります。
ツール名 | 用途 |
---|---|
RustRover 2024.2 | Rust 開発者向けのIDEです。個人非商用利用は無料となっています。 |
Docker Desktopのインストールは、以下の記事を参考にしてください。
端末
以下、今回の環境を構築する対象の端末スペックです。
項目 | 詳細 |
---|---|
ハードウェア | Apple Silicon M3, RAM 24GB |
OS | macOS Sonoma 14.6 |
本記事で紹介するソフトウェアおよびツールは、筆者の個人的な使用経験に基づくものであり、公式のサポート外の設定や使用方法を含む場合があります。利用に際しては、公式サイトの指示およびガイドラインを参照し、自己責任で行ってください。
Rust開発環境の構築
Rustのインストール
Rustをインストールするには、公式のインストーラーツールであるrustupを使用します。rustupは、Rustの最新のツールチェーンをインストールおよび管理するためのツールです。
手順
- ターミナルを開く
- macOSでターミナルを開きます。
- rustupを使用してRustをインストール
- 以下のコマンドをターミナルに入力して、Rustとcargoをインストールします。
curl --proto '=https' --tlsv1.2 -sSf <https://sh.rustup.rs> | sh
コマンド実行後の画面です。
インストールをデフォルトで行うか、カスタマイズするか、キャンセルするか、の選択肢が表示されています。ここでは、デフォルトを選択します。(エンターキーのみの入力でOKです)

インストールが始まります。「Rust is installed now. Great!」のメッセージが出力されていればインストールは成功です。

環境変数を有効にするために、ターミナルを再起動するか以下のコマンドで有効にしてください。
source $HOME/.cargo/env
以下のコマンドをターミナルで実行して、cargoが正しくインストールされたかを確認します。
cargo --version
正しくインストールされていれば、Cargoのバージョンが表示されます。例えば、cargo 1.x.x (yyyy-mm-dd)のように表示されます。
(base) xxxxx@xxxxx rust_countdown % cargo --version
cargo 1.80.1 (376290515 2024-07-16)
(base) xxxxx@xxxxx rust_countdown %
Rustの開発に必要なツール群は、$HOME/.cargo/binにインストールされています。
今回の環境であれば、以下の出力となります。
(base) xxxxx@xxxxx ~ % cd $HOME/.cargo/bin
(base) xxxxx@xxxxx bin % ls
cargo cargo-miri rust-analyzer rust-lldb rustfmt
cargo-clippy clippy-driver rust-gdb rustc rustup
cargo-fmt rls rust-gdbgui rustdoc
(base) xxxxx@xxxxx bin %
カウントダウンアプリの開発
Rust プロジェクトの準備
手順
- プロジェクトの作成
- Rustのプロジェクトを作成するために、cargo new rust_countdownというコマンドを使います。
- これにより、rust_countdownという名前のディレクトリが作成され、その中にプロジェクトの基本的なファイルが生成されます。
プロジェクト作成コマンド
cargo new rust_countdown
プロジェクト作成時のログ
筆者の場合は、test-pjディレクトリにて実行しています。このディレクトリは任意のディレクトリでOKです。
(base) xxxxx@xxxxx test-pj % cargo new rust_countdown
Creating binary (application) `rust_countdown` package
note: see more `Cargo.toml` keys and their definitions at <https://doc.rust-lang.org/cargo/reference/manifest.html>
(base) xxxxx@xxxxx test-pj %
プロジェクトディレクトリに移動
先ほど作成したrust_countdownディレクトリに移動します。
cd rust_countdown
プロジェクトディレクトリへ移動し、treeコマンドでディレクトリの内容を表示したログです。
(base) xxxxx@xxxxx test-pj % cd rust_countdown
(base) xxxxx@xxxxx rust_countdown % tree .
.
├── Cargo.toml
└── src
└── main.rs
2 directories, 2 files
(base) xxxxx@xxxxx rust_countdown %
プロジェクト作成コマンドにより、以下のディレクトリとファイルが生成されます。
- プロジェクトディレクトリ: rust_countdown
- 生成されるファイル:
- Cargo.toml: プロジェクトの依存関係やメタデータを管理するファイル
- src/main.rs: Rustのメインプログラムファイル
カウントダウンタイマーのプログラム作成
main.rsにプログラムを記述します。
src/main.rsファイルを開き、以下のコードを記述します。コードの詳細な解説は、以降で行います。
use std::io;
use std::thread;
use std::time::Duration;
fn main() {
let seconds = get_user_input();
start_countdown(seconds);
display_end_message();
}
fn get_user_input() -> u32 {
loop {
println!("Please enter the countdown time in seconds:");
let mut input = String::new();
io::stdin().read_line(&mut input).expect("Failed to read input");
match input.trim().parse::<u32>() {
Ok(seconds) => return seconds,
Err(_) => println!("Invalid input. Please enter a positive integer."),
}
}
}
fn start_countdown(seconds: u32) {
for remaining in (1..=seconds).rev() {
println!("Time left: {} seconds", remaining);
thread::sleep(Duration::from_secs(1));
}
}
fn display_end_message() {
println!("Time's up!");
}
アプリの実行
Dockerファイルの作成
カウントダウンタイマーを実行するためのコンテナイメージの定義ファイルを作成します。
手順
- Dockerfileの作成
- プロジェクトのルートディレクトリ(rust_countdownディレクトリ)にDockerfileという名前のファイルを作成し、以下の内容を記述します。
- このファイルは、Rustプログラムをコンテナ内でビルドして実行するための指示書です。
Dockerfile
# ベースイメージとしてRustを指定
FROM rust:latest
# 作業ディレクトリを指定
WORKDIR /usr/src/app
# Cargo.tomlとソースコードをコンテナにコピー
COPY Cargo.toml .
COPY src ./src
# 依存関係をダウンロードしてビルド
RUN cargo build --release
# 実行可能ファイルを実行
CMD ["./target/release/rust_countdown"]
プロジェクトのビルドと実行
カウントダウンタイマーのビルドと実行を行います。
以下のコマンドをプロジェクトのルートディレクトリで実行します。これにより、Dockerfileを使ってコンテナイメージをビルドし、カウントダウンタイマーを実行します。
コンテナイメージのビルドコマンド
ビルドしたコンテナイメージ名に「rust_countdown」を指定しています。
docker build . -t rust_countdown
イメージビルドのログです。Rustで作ったアプリがCargoでビルドされているのが分かりますね。
(base) xxxxx@xxxxx rust_countdown % docker build . -t rust_countdown
[+] Building 0.8s (10/10) FINISHED docker:desktop-linux
=> [internal] load build definition from Dockerfile 0.0s
=> => transferring dockerfile: 446B 0.0s
=> [internal] load metadata for docker.io/library/rust:latest 0.7s
=> [internal] load .dockerignore 0.0s
=> => transferring context: 2B 0.0s
=> [1/5] FROM docker.io/library/rust:latest@sha256:29fe4376919e25b7587a1 0.0s
=> [internal] load build context 0.0s
=> => transferring context: 122B 0.0s
=> CACHED [2/5] WORKDIR /usr/src/app 0.0s
=> CACHED [3/5] COPY Cargo.toml . 0.0s
=> CACHED [4/5] COPY src ./src 0.0s
=> CACHED [5/5] RUN cargo build --release 0.0s
=> exporting to image 0.0s
=> => exporting layers 0.0s
=> => writing image sha256:789d1daaa13f70eaf61670bc9f2b5a4d6037bd8817ac6 0.0s
=> => naming to docker.io/library/rust_countdown 0.0s
View build details: docker-desktop://dashboard/build/desktop-linux/desktop-linux/wf39hvxnftaomxe9zpviccs56
What's next:
View a summary of image vulnerabilities and recommendations → docker scout quickview
docker imagesコマンドで、イメージが正常に作成されているか確認します。
「rust_countdown」が作成されていれば成功です。
(base) xxxxx@xxxxx rust_countdown % docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
rust_countdown latest 789d1daaa13f 59 minutes ago 1.76GB
ビルドしたコンテナイメージの実行コマンド
docker run -it rust_countdown
rust_countdownアプリが起動して、入力待ちになります。
ここでは、4秒のカウントダウンを行いました。
(base) xxxxx@xxxxx rust_countdown % docker run -it rust_countdown
Please enter the countdown time in seconds:
4
Time left: 4 seconds
Time left: 3 seconds
Time left: 2 seconds
Time left: 1 seconds
Time's up!
(base) xxxxx@xxxxx rust_countdown %
コードの解説
Rustのmain.rs
ファイルに書かれたカウントダウンタイマーのプログラムをRustの基本機能(学習ポイント)毎に解説します。
- 標準入力の取り扱い
- エラーハンドリング
- 時間操作
- シンプルなループと条件分岐
学習ポイント 1: 標準入力の取り扱い
標準入力とは?
標準入力は、コンピュータにデータや情報を渡す方法の一つです。例えば、キーボードから何かを入力して、それをプログラムに渡すことが標準入力です。このプログラムでは、カウントダウンする秒数をキーボードから入力します。
コードの該当箇所
let mut input = String::new();
io::stdin().read_line(&mut input).expect("Failed to read input");
let mut input = String::new();
input
という変数を作って、そこに入力されたテキストを保存します。String::new()
は、空っぽの文字列を作るための方法です。ここでmut
を使っているのは、このinput
という変数に後からデータを入れたり変えたりするからです。
io::stdin().read_line(&mut input).expect("Failed to read input");
io::stdin()
は、「標準入力」を使うためのコマンドです。read_line
という関数を使って、キーボードから入力されたテキストを読み込み、それをinput
に入れます。&mut input
は、「input
という変数を使って、データをここに入れてね」とRustに伝えています。expect("Failed to read input")
は、もし入力がうまくいかなかった場合に「Failed to read input」というメッセージを出してくれます。
学習ポイント 2: エラーハンドリング
エラーハンドリングとは?
エラーハンドリングとは、プログラムが何か間違いを起こしたときに、それをどうやって処理するかを決めることです。プログラムが突然止まらないようにするために、エラーハンドリングはとても大切です。
コードの該当箇所
match input.trim().parse::<u32>() {
Ok(seconds) => return seconds,
Err(_) => println!("Invalid input. Please enter a positive integer."),
}
input.trim().parse::<u32>()
input
は、さっきキーボードから入力された文字が入っている変数です。trim()
は、余分なスペースを消す関数で、parse::<u32>()
は、この文字列をu32
(正の整数)に変換しようとします。
match
match
は、「これがうまくいったかどうか」をチェックするための構文です。文字列をu32
(正の整数)への変換がチェック対象です。
Ok(seconds) => return seconds,
- もし変換がうまくいったら、その値を
seconds
という名前で取り出して、関数の結果として返します(return
)。
- もし変換がうまくいったら、その値を
Err(_) => println!("Invalid input. Please enter a positive integer."),
- もし変換が失敗したら(例えば、文字やマイナスの数字を入力した場合)、エラーメッセージを表示します。
学習ポイント 3: 時間操作
時間操作とは?
時間操作は、プログラムが「何秒待つ」といった時間に関する処理をすることです。例えば、カウントダウンタイマーでは、1秒ごとに時間を減らしていく必要があります。
コードの該当箇所
thread::sleep(Duration::from_secs(1));
thread::sleep(Duration::from_secs(1));
- このコードは、プログラムに「1秒待ってね」と伝えるものです。
thread::sleep
は、「スレッド(プログラムの一部)を一時停止させる」という意味です。そして、Duration::from_secs(1)
は、「1秒間」という時間を作り出します。
- このコードは、プログラムに「1秒待ってね」と伝えるものです。
学習ポイント 4: シンプルなループと条件分岐
ループと条件分岐とは?
- ループは、同じ処理を何度も繰り返すことです。
- 条件分岐は、「もし~ならばこうする」という判断をプログラムにさせることです。
コードの該当箇所
for remaining in (1..=seconds).rev() {
println!("Time left: {} seconds", remaining);
thread::sleep(Duration::from_secs(1));
}
for remaining in (1..=seconds).rev()
- これはループの一つの形で、「1から
seconds
までの数字を逆順にカウントダウンする」ループです。remaining
には、現在の秒数が入ります。例えば、seconds
が10ならば、このループは10から1まで繰り返されます。
- これはループの一つの形で、「1から
println!("Time left: {} seconds", remaining);
remaining
の秒数を表示します。例えば、「Time left: 5 seconds」といった形で、今残り何秒かを画面に出します。
thread::sleep(Duration::from_secs(1));
- ここで、1秒待機してから次の秒数に進みます。これにより、1秒ごとにカウントダウンが進むようになります。
まとめ
環境構築・アプリ開発・実行までの手順
本記事では、Rustの開発環境を構築してアプリ開発を行い、そのアプリをDockerコンテナを使って実行しました。
これは、Rustで開発する際の基本となる手順の一つとなります。以下に、おさらいとしてサマリーをまとめますので、頭の中を整理してみてください。
- Rust開発環境の構築
- Rustのプロジェクトを作成し、ディレクトリと基本ファイルを用意します。
- カウントダウンアプリの開発
- src/main.rsにカウントダウンタイマーのコードを書きます。
- アプリの実行
- Rustプログラムをコンテナ内でビルドして実行するためのDockerfile、docker-compose.ymlを作成します。
- docker compose up –buildコマンドで、Dockerコンテナ内でRustのカウントダウンタイマーを実行します。
Rustの実装イメージ
本記事で、シンプルなCLIアプリでRustの基本機能とその実装イメージをについて紹介しました。
以下に、Rustの基本機能に対応した実装のポイントをまとめます。
- 標準入力の取り扱い
- 標準入力の取り扱い:
io::stdin().read_line()
で、キーボードから入力されたテキストを読み取ります。
- 標準入力の取り扱い:
- エラーハンドリング
- エラーハンドリング:
match
とexpect
を使って、入力が間違っているかどうかをチェックし、エラーがあればそれを適切に処理します。
- エラーハンドリング:
- 時間操作
- 時間操作:
thread::sleep(Duration::from_secs(1))
を使って、プログラムに1秒待たせます。
- 時間操作:
- シンプルなループと条件分岐
- シンプルなループと条件分岐:
for
ループと条件分岐を使って、カウントダウンを1秒ごとに表示しながら進めます。
- シンプルなループと条件分岐:
【筆者の一言】
今回Rustを初めて使いましたが、感想としてはかなり適用可能性が広いプログラム言語だなと感じます。筆者は元々C/C++からアプリ開発の世界に入りました。作成するアプリの特性や用途に合わせて、色々なプログラム言語を学んできましたが、開発しやすいが速度が遅い、開発しにくいがバグが発生しやすいなど色々と苦労しました。Rustには、それを解決してくれる可能性を感じたので、これからの進化に期待しつつ深掘りしていく予定です。
初心者の皆さんに取っては、コンピュータの仕組みをもっと深く知りたい、しっかりしたプログラムを作りたい人にとって、とても魅力的なプログラム言語なので、お薦めです。
これからもRustとDockerコンテナを活用して、より高度なアプリケーション開発に挑戦してみてください!
最後に、この記事がRustの学習やアプリ開発に役立つことを願っています。