
Rust 入門 - rustup でインストールして、コラッツ数列ツールで動作確認する
「速くて安全」と評判の Rust。名前は知っていても、所有権やライフタイムの話を聞いて身構えてしまう人は多いと思います。この記事では、Rust の特徴を手短に押さえ、公式ツール rustup でのインストール、Cargo の基本操作を通したうえで、動作確認用に書いた小さな CLI ツール(コラッツ数列ジェネレータ)を題材に「Rust らしい書き方」を実際の出力つきで見ていきます。
検証環境は Rust 1.96.0(2026-05-25)/ edition 2024 です。
Rust とは
Rust は、メモリ安全性とパフォーマンスを両立することを目的に設計されたシステムプログラミング言語です。要点を絞るとこうなります。
- 所有権(ownership)と借用(borrowing): 値の寿命をコンパイラが追跡し、ガベージコレクタ(GC)なしでメモリ安全を保証する。use-after-free やデータ競合をコンパイル時に弾くのが最大の特徴
- GC なしで高速: ランタイムが薄く、C / C++ に並ぶ速度域。実行時のメモリ管理コストがない
- 強力な型と網羅的なエラー設計: 失敗しうる処理は
Result<T, E>、値が無いかもしれない場面はOption<T>で表現し、matchや?演算子で取りこぼしにくい - Cargo というオールインワン: ビルド・依存管理・テスト・ドキュメント生成・公開(crates.io)まで標準ツールで完結する
- edition 制: 言語を進化させつつ後方互換を保つ仕組み。2015 / 2018 / 2021 / 2024 と区切られ、プロジェクトごとに選べる
WebAssembly へのコンパイルも得意で、ブラウザの外まで活躍の場が広がっています(WebAssembly はブラウザの外へ)。フロントエンドのツールチェーンが Rust で書き直される流れ(Oxc / Oxlint)も、この速度と安全性が背景にあります。
rustup でインストールする
Rust の導入は、公式のツールチェーン管理ツール rustup を使うのが基本です。Unix 系(macOS / Linux)は次の1行で入ります。
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | shこれで以下がまとめて入り、~/.cargo/bin に配置されます。
| ツール | 役割 |
|---|---|
rustc | Rust コンパイラ本体 |
cargo | ビルド・依存管理・テスト等のフロントエンド |
rustup | ツールチェーン(バージョン)管理ツール |
インストール後、PATH の反映のためにターミナルを開き直すのが確実です(rustup が PATH 設定を試みますが、シェルによっては再起動まで効かないことがあります)。入ったか確認します。
rustc --version # rustc 1.96.0 (ac68faa20 2026-05-25)
cargo --version # cargo 1.96.0 (30a34c682 2026-05-25)rustup でよく使う操作はこのあたりです。
rustup update # 安定版を最新へ更新
rustup show # 現在のツールチェーンを表示
rustup component add clippy # リンタ clippy を追加
rustup self uninstall # Rust をまるごとアンインストール複数バージョン(stable / beta / nightly)を切り替えられるのが rustup の強みです。プロジェクト直下に rust-toolchain.toml を置けば、そのリポジトリで使うバージョンを固定することもできます。
Cargo の基本
開発はほぼ Cargo 経由で進みます。新規プロジェクトの作成から実行・テストまでを通すとこうなります。
cargo new collatz # collatz/ に雛形を生成(Cargo.toml と src/main.rs)
cd collatz
cargo run # ビルドして実行(デバッグビルド)
cargo run -- 27 # -- 以降はプログラムへの引数
cargo test # テストを実行
cargo build --release # 最適化付きのリリースビルド
cargo fmt # コード整形
cargo clippy # 静的解析(リンタ)cargo new が吐く Cargo.toml がプロジェクトの設定ファイルで、依存(crate)もここに書きます。今回のツールは標準ライブラリだけで完結するので、依存は空のままです。
[package]
name = "collatz"
version = "0.1.0"
edition = "2024"
[dependencies]動作確認に書いたコード: コラッツ数列ジェネレータ
ツールチェーンが入ったので、動作確認用に小さな CLI を書きました。題材はコラッツ数列です。「正の整数を、偶数なら2で割り、奇数なら3倍して1を足す」を繰り返すと、どんな数からでも最後は1に到達する、という有名な未解決問題(コラッツ予想)の数列です。
正の整数を受け取り、数列・ステップ数・途中の最大値(peak)を表示します。中心となる計算部分がこれです。
/// コラッツ数列の計算結果。
struct Collatz {
start: u64,
sequence: Vec<u64>,
/// 数列の最大値(途中でどこまで大きくなったか)。
peak: u64,
}
impl Collatz {
/// `start` から 1 までのコラッツ数列を計算する。
/// オーバーフローした場合は `Err` を返す。
fn compute(start: u64) -> Result<Self, String> {
if start == 0 {
return Err("0 は対象外です(正の整数を入力してください)".to_string());
}
let mut sequence = vec![start];
let mut current = start;
while current != 1 {
current = if current % 2 == 0 {
current / 2
} else {
// 3n + 1。巨大な入力でのオーバーフローを安全に検出する。
current
.checked_mul(3)
.and_then(|v| v.checked_add(1))
.ok_or_else(|| format!("{start} の計算中に u64 がオーバーフローしました"))?
};
sequence.push(current);
}
let peak = *sequence.iter().max().expect("数列は必ず1要素以上ある");
Ok(Collatz { start, sequence, peak })
}
}短いコードですが、Rust らしさが詰まっています。
- 失敗を型で表す:
computeはResult<Self, String>を返す。0 入力やオーバーフローは例外ではなくErrとして返し、呼び出し側に処理を強制する - オーバーフローを握り潰さない:
3 * n + 1を素朴に書くと巨大な入力でu64が溢れる。checked_mul/checked_addは溢れたらNoneを返すので、?でエラーに変換して安全に止められる(リリースビルドの整数オーバーフローは黙って値が回り込むため、これを明示的に防ぐのが定石) - 所有権が自然に効く:
sequenceはCollatzが所有し、peakはそこから計算する。手動の解放は要らない
引数処理と表示を行う main 側では、複数の数をまとめて処理し、1つでも失敗したら終了コードを 1 にしています。
fn main() {
let args: Vec<String> = env::args().skip(1).collect();
if args.is_empty() {
eprintln!("使い方: cargo run -- <正の整数> [<正の整数> ...]");
process::exit(2);
}
let mut had_error = false;
for arg in &args {
if let Err(e) = run(arg) {
eprintln!("エラー: {e}");
had_error = true;
}
}
if had_error {
process::exit(1);
}
}実行してみる
cargo run -- 6 11 27 で3つまとめて流すと、こうなります。
6 -> steps: 8, peak: 16
6 -> 3 -> 10 -> 5 -> 16 -> 8 -> 4 -> 2 -> 1
11 -> steps: 14, peak: 52
11 -> 34 -> 17 -> 52 -> 26 -> 13 -> 40 -> 20 -> 10 -> 5 -> 16 -> 8 -> 4 -> 2 -> 1
27 -> steps: 111, peak: 923227 は111 ステップ・ピーク 9232という、小さい入力なのに大きく暴れる有名なケースです(数列が長いので展開表示は省略されます)。不正な入力もきちんとエラーになります。
エラー: 0 は対象外です(正の整数を入力してください)
エラー: 'abc' は正の整数として解釈できませんテストも同居させる
Rust はテストを同じファイルに書けるのが手軽です。#[cfg(test)] を付けたモジュールはテスト時だけコンパイルされます。
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn sequence_for_six() {
let c = Collatz::compute(6).unwrap();
assert_eq!(c.sequence, vec![6, 3, 10, 5, 16, 8, 4, 2, 1]);
assert_eq!(c.steps(), 8);
assert_eq!(c.peak, 16);
}
#[test]
fn classic_twenty_seven() {
// 27 は 111 ステップ・ピーク 9232 で有名なケース。
let c = Collatz::compute(27).unwrap();
assert_eq!(c.steps(), 111);
assert_eq!(c.peak, 9232);
}
#[test]
fn zero_is_rejected() {
assert!(Collatz::compute(0).is_err());
}
}cargo test を実行すると、全件パスします。
running 4 tests
....
test result: ok. 4 passed; 0 failed; 0 ignored; 0 measured; 0 filtered outビルド・実行・テストまで、追加の設定ファイルや依存なしに cargo のコマンドだけで完結しました。これが Rust(と Cargo)の気持ちよさです。
触ってみて感じたこと
- コンパイラが厳しいぶん、通れば安心感がある: 所有権・型・エラー処理を最初に詰められるので、コンパイルが通った時点で素朴なバグはかなり潰れている
- エラー処理が「例外で飛ぶ」のではなく「値で返る」:
Resultと?のおかげで、失敗経路が型に現れて読みやすい - 標準ツールが揃っている:
cargo fmt/cargo clippy/cargo testまで標準。最初から「ちゃんとした開発」の土台が用意されている
最初の学習コスト(特に所有権・借用)は確かにありますが、小さな CLI を1つ完成させるだけでも、その厳しさが「うるさい同僚」ではなく「先回りしてくれる安全装置」だと体感できます。
まとめ
- Rust は所有権・借用でメモリ安全を保証し、GC なしで高速なシステム言語。
Result/Optionによる明示的なエラー設計と、Cargo によるオールインワンな開発体験が強み - 導入は rustup の1コマンド。
rustc/cargo/rustupが~/.cargo/binに入る。更新はrustup update、削除はrustup self uninstall - 開発は Cargo 中心。
cargo new/run/test/build --release/fmt/clippyで一通り回る - 動作確認のコラッツツールでは、
Resultでのエラー処理・checked_mulでのオーバーフロー対策・構造体とテストの同居といったRust らしい書き方を、依存ゼロで実装できた - 検証は Rust 1.96.0 / edition 2024。
cargo runとcargo test(4件)まで実機で確認済み
「速くて安全」は単なる宣伝文句ではなく、コンパイラと型がそれを担保してくれる——小さなツールを1本書くだけで、その手触りがつかめます。まずは rustup を入れて、cargo new から始めてみてください。