- 技術 💻
Rust言語とは?特徴・できること・入門|所有権エラーと速度を実測
結論
Rust(ラスト)は、C・C++並みの速さと、メモリの誤りをコンパイル時に止める安全性を両立したプログラミング言語です。ガベージコレクション(GC)を使わず、「所有権」という決まりでメモリを管理します。
この記事でわかること
- Rustの特徴・できること・使われている場面(公開情報)
- 所有権・借用のコンパイルエラー9種の原文と直し方
- C・Go・Pythonと同じ処理の速度・メモリの実測
Rust の道具は3つの役割に分かれています。公式のインストーラー rustup が版を管理し、cargo がビルドと依存を、rustc がコンパイルを受け持ちます。
flowchart TD
U[rustup<br>版の管理] --> C[cargo<br>ビルド・依存・テスト]
U --> R[rustc<br>コンパイラ]
C -->|依存を取得| IO[crates.io]
C -->|呼び出す| R
R --> B[実行ファイル]
よく調べられることの答えを先にまとめます。
| 知りたいこと | 答え | 詳しい節 |
|---|---|---|
| Rust言語とは | 速さとメモリ安全を両立したコンパイル型の言語 | Rust言語とは |
| 読み方・最新版 | ラスト。2026年10月29日時点の安定版は 1.99.1 | Rust言語とは |
| Rustでできること | CLI・Webサーバー・OS・ブラウザ・WebAssembly・組み込み | できること・使われている場面 |
| Rustのインストール | 公式は rustup。Windows は MSVC のビルドツールも要る | インストール |
| Rust入門の最初の一歩 | cargo new → cargo run |
Hello World と cargo new |
| 難しいと言われる理由 | 所有権・借用のコンパイルエラーに慣れるまで | 所有権・借用 |
| どれくらい速いか | 手元の計測でCと同程度、Pythonの数倍〜約55倍 | 速度・メモリ比較 |
| 何から学ぶか | The Book 日本語版 → Rustlings → 小さなCLI | 学ぶ順番 |
確認環境:Ubuntu 24.04.5 LTS(2 vCPU の仮想マシン)に、apt で rustc-1.91・cargo-1.91・rustfmt-1.91・rust-1.91-clippy(いずれも 1.91.1)を入れ、CARGO_HOME とプロジェクトは作業用のフォルダーに置いて動かしました。コンパイルエラー・テスト・crates.io からの依存の取得(ferris-says)・clippy の出力は、すべて手元で実行した原文です。速度の比較は gcc 13.3.0(-O2)・Go 1.24.7・Python 3.13.18 で同じ処理を書き、5回の中央値をとりました。rustup によるインストール・Windows の前提条件・最新版の番号・エディションは、Rust 公式サイト・rustup の公式ドキュメント・Rust 公式ブログで確かめ、採用事例は各社の公開情報で確かめています。図は mermaid で描画を確かめました(確認日 2026年10月29日)。
本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。
(記載例)出典:株式会社RJC「Rust言語とは?特徴・できること・入門|所有権エラーと速度を実測」
Rust言語とは(読み方・歴史・最新バージョン)
この節では、Rust がどんな言語で、いつ生まれ、今どの版なのかが分かります。
Rust は、OS やブラウザのような「速さが要る土台のソフト」を、メモリの誤りなく書くために作られたプログラミング言語です。 読み方は「ラスト」で、英語の rust(さび)と同じ綴りです。同じ名前のサバイバルゲーム「Rust」とは関係ありません。
| 項目 | 内容 |
|---|---|
| 種類 | コンパイル型(実行前に機械語へ変換する)・静的型付け |
| メモリ管理 | GC なし。所有権の決まりで、使い終わった値をその場で解放する |
| 1.0 の公開 | 2015年5月15日(Rust 公式ブログ) |
| リリースの間隔 | 6週間ごとに新しい安定版(公式のインストールページ) |
| 最新の安定版 | 1.99.1(2026年10月15日公開。2026年10月29日時点) |
| 運営 | オープンソースの Rust プロジェクト。2021年に Rust Foundation ができ、AWS・Google・Microsoft などが創設時の会員 |
エディション(2015・2018・2021・2024)
Rust は「1.x」の番号を上げ続けながら、書き方が変わる変更だけを数年に1度のエディションにまとめます。Cargo.toml の edition でプロジェクトごとに選び、エディションが違うクレート(Rust のパッケージ)同士もそのまま組み合わせて使えます(Edition Guide)。
| エディション | 使えるようになった版 | 公開日 |
|---|---|---|
| 2015 | 1.0 | 2015年5月15日 |
| 2018 | 1.31 | 2018年12月6日 |
| 2021 | 1.56.0 | 2021年10月21日 |
| 2024 | 1.85.0 | 2025年2月20日 |
手元の cargo 1.91.1 で cargo new すると、edition = "2024" が書かれました。2024 エディションのプロジェクトは 1.85 より前の rustc ではビルドできません。Ubuntu 24.04 の rustc パッケージ(版の番号なし)は 1.75.0 だったため、apt で入れるときは rustc-1.91 のような版付きのパッケージを選びました。
Rustの特徴(速さ・メモリ安全・ツール)
この節では、Rust が他の言語と比べて何が違うのかが、4つの点で分かります。
1C・C++並みに速い
機械語にコンパイルし、GC の停止もない。手元のふるいの計測では C(gcc -O2)と同じ水準だった。
2メモリの誤りをコンパイルで止める
解放後の利用・二重解放・データ競合を、所有権と借用の検査(ボローチェッカー)がビルド時にエラーにする。
3null と例外がない
「値が無いかも」は Option、「失敗するかも」は Result という型で表し、扱い忘れはコンパイルエラーになる。
4道具が最初から揃う
cargo 1つで作成・ビルド・テスト・依存管理。整形の rustfmt、検査の clippy も公式の道具。
エラーメッセージが丁寧なのも特徴です。この記事に載せたコンパイルエラーの多くは、help: の行に直し方(.clone() を足す、move を付ける など)までが書かれていました。エラー番号の詳しい説明は rustc --explain E0382 のように番号を渡すと表示されます。
$ rustc --explain E0382
A variable was used after its contents have been moved elsewhere.
Erroneous code example:
...
Rustでできること・使われている場面
この節では、Rust で何が作れて、どの会社・プロジェクトがどこで使っているのかが、公開情報で分かります。
| 分野 | できること・代表例 |
|---|---|
| コマンドラインツール | 1つの実行ファイルで配れる。検索ツール ripgrep など |
| Web サーバー・API | Axum・Actix Web・Rocket などのフレームワーク、非同期処理の Tokio |
| OS・カーネル・仮想化 | Linux カーネルのドライバー、AWS の Firecracker |
| ブラウザ・スマホの OS | Firefox の一部、Android の新しいコード |
| WebAssembly | ブラウザで動く .wasm を作れる(wasm32 向けのターゲットがある) |
| 組み込み | マイコン向け(公式の Embedded Book がある) |
| デスクトップアプリ・ゲーム | Tauri(画面は Web 技術)、ゲームエンジン Bevy |
公開されている採用の情報
- Android(Google):2025年11月13日の Google のブログは、Android の Rust のコードは C・C++ と比べてメモリ安全性の脆弱性の密度が約1000分の1(Rust は 100万行あたり 0.2件の見積もり、C・C++ は約1,000件)、中〜大きな変更の取り消し(ロールバック)率が約4分の1、コードレビューの時間が約25%短い、と報告しています。
- Linux カーネル:LWN.net(2025年12月10日)によると、年次の Maintainers Summit で、カーネルの Rust は「実験」の段階を終えたと合意されました。
- Discord:2020年2月4日の公式ブログで、既読の状態を管理するサービス(Read States)を Go から Rust に書き直し、GC による約2分ごとの遅延の山が消えたと説明しています。
- AWS:Firecracker の公式サイトは「Firecracker is written in Rust」と書き、AWS Lambda を支える技術だと説明しています。
- Microsoft:Microsoft Learn に Windows で Rust を使う手順と
windowsクレートの案内があり、Microsoft は Rust Foundation の創設時の会員だと書かれています。 - 開発者の評価:Stack Overflow Developer Survey 2025 で、Rust は「admired(使っている人がまた使いたい)」が 72.4% で1位でした。使っている人の割合は 14.8% です。
米国の CISA と NSA は 2025年6月24日に、メモリ安全な言語(MSL)への移行を勧める共同の資料を出しました。Rust はこの「メモリ安全な言語」の代表として名前が挙がることが多い言語です。
Rustのインストール(rustup・apt・Windows)
この節では、Windows・Mac・Linux で Rust を入れる公式の手順と、入ったかの確かめ方が分かります。
公式の入れ方は rustup です。 rustup が rustc・cargo・標準ライブラリをまとめて入れ、版の更新も受け持ちます。手順は Rust 公式サイトと rustup の公式ドキュメントで確かめました(この記事の環境では rustup は使わず、apt の版付きパッケージで動かしています)。
Mac・Linux・WSL:ターミナルで rustup を実行
公式サイトの curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh を実行し、表示に従う。WSL も同じコマンド。
Windows:rustup-init.exe を実行
公式サイトから 64bit(x64)・ARM64・32bit の rustup-init.exe を選んで実行する。MSVC のビルドツール(Visual Studio の「C++ によるデスクトップ開発」)が要り、rustup-init が自動で入れるかを尋ねる。
ターミナルを開き直す
道具は ~/.cargo/bin(Windows は %USERPROFILE%\.cargo\bin)に入る。PATH の変更は、ターミナルを開き直すまで効かないことがある。
版を確かめる
rustc --version と cargo --version。動かないときは PATH がいちばん多い原因、と公式サイトにある。
更新・削除
更新は rustup update、削除は rustup self uninstall。
手元の Ubuntu では、版付きのパッケージで入れました。版付きのパッケージはコマンドの名前にも版が付き、/usr/lib/rust-1.91/bin を PATH に足すと rustc・cargo の名前で使えます。
$ sudo apt install rustc-1.91 cargo-1.91
$ rustc-1.91 --version
rustc 1.91.1 (ed61e7d7e 2025-11-07) (built from a source tarball)
$ export PATH=/usr/lib/rust-1.91/bin:$PATH
$ cargo --version
cargo 1.91.1 (ea2d97820 2025-10-10) (built from a source tarball)
apt の版は rustup より遅れます(2026年10月29日時点で、手元の apt の最新は 1.91、公式の安定版は 1.99.1)。複数の版の切り替えや、WebAssembly などのターゲットの追加は rustup のほうが簡単です。インストールせずに試すなら、ブラウザで動く公式の Rust Playground(play.rust-lang.org)が使えます。
Hello World と cargo new(Rust入門の最初の一歩)
この節では、rustc で1ファイルをコンパイルする方法と、cargo でプロジェクトを作り、依存を足して動かすまでが、実行結果で分かります。
rustc で直接コンパイルする
fn main() {
println!("Hello, world!");
}
$ rustc hello.rs # 0.30秒
$ ./hello
Hello, world!
println! の ! は、関数ではなくマクロであることを示します。できた hello は単体で動く実行ファイルで、Python と違い、実行する側に処理系を入れずに動きます。
cargo new でプロジェクトを作る
実際の開発は cargo を使います。cargo new は、設定ファイル・ソース・.gitignore を作り、Git のリポジトリも初期化しました。
$ cargo new hello-rust
Creating binary (application) `hello-rust` package
$ cd hello-rust && ls -a
. .. .git .gitignore Cargo.toml src
$ cat Cargo.toml
[package]
name = "hello-rust"
version = "0.1.0"
edition = "2024"
[dependencies]
$ cargo run
Compiling hello-rust v0.1.0 (/dev/shm/t37/hello-rust)
Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.31s
Running `target/debug/hello-rust`
Hello, world!
| コマンド | すること | できるもの |
|---|---|---|
cargo new 名前 |
プロジェクトを作る(--lib でライブラリ) |
Cargo.toml・src/main.rs |
cargo build |
開発用にビルド(最適化なし) | target/debug/ |
cargo run |
ビルドして実行 | 同上 |
cargo build --release |
最適化してビルド(配布・計測用) | target/release/ |
cargo check |
コンパイルの検査だけ(速い) | なし |
cargo test |
テストを実行 | 結果の一覧 |
cargo add クレート名 |
依存を Cargo.toml に足す | [dependencies] の行 |
cargo doc --open |
ドキュメントを作って開く | target/doc/ |
依存クレートを足す(crates.io)
公式の「はじめに」と同じ ferris-says を足しました。cargo add が Cargo.toml に行を足し、最初の cargo run で crates.io から取得してビルドします。
$ cargo add ferris-says@0.3.1
Updating crates.io index
Adding ferris-says v0.3.1 to dependencies
Locking 40 packages to latest Rust 1.91.1 compatible versions
$ cargo run
Downloaded ferris-says v0.3.2
...
Compiling ferris-says v0.3.2
Compiling ferris-demo v0.1.0 (/dev/shm/t37/ferris-demo)
Finished `dev` profile [unoptimized + debuginfo] target(s) in 29.44s
__________________________
< Hello fellow Rustaceans! >
--------------------------
\
\
_~^~^~_
\) / o o \ (/
'_ - _'
/ '-----' \
"0.3.1"と書いても 0.3.2 が入りました。 Cargo の版の指定は、何も付けないと「0.3.1 以上で互換のある版」という意味です。実際に使った版はCargo.lockに記録されます。- 依存1つで、間接の依存を含めて 40 個のクレートを取得し、最初のビルドに 29.4 秒かかりました。
targetフォルダーは 346.9MiB になりました(cargo cleanの表示)。容量の小さい環境ではtargetの大きさに気を付けます。 - crates.io を使えない環境では、手元のクレートを
pathで指定できます。下の節で作ったwordfreqを、別のプロジェクトから使った例です。
[dependencies]
wordfreq = { path = "../wordfreq" }
$ echo "the cat and the dog and THE bird" | cargo run -q
3 the
2 and
1 bird
Rustの基本文法(変数・型・struct・enum・match・トレイト)
この節では、Rust 入門で最初に押さえる文法が、1本のプログラムと実行結果で分かります。
struct Rect { w: u32, h: u32 } // 構造体
impl Rect {
fn area(&self) -> u32 { self.w * self.h } // メソッド
}
enum Shape { Circle(f64), Square(f64) } // 列挙型(値を持てる)
fn area(s: &Shape) -> f64 {
match s { // すべての場合を書く
Shape::Circle(r) => 3.14159 * r * r,
Shape::Square(a) => a * a,
}
}
trait Greet { fn hello(&self) -> String; } // トレイト(共通の振る舞い)
impl Greet for Rect {
fn hello(&self) -> String { format!("{}x{} の長方形です", self.w, self.h) }
}
fn main() {
let x = 5; // 既定では変更できない
let mut y = 10; // mut を付けると変更できる
y += x;
let x = x * 2; // シャドーイング(同じ名前で新しい変数)
let kind = if y > 10 { "大" } else { "小" }; // if は値を返す式
println!("x={x} y={y} kind={kind}");
let r = Rect { w: 3, h: 4 };
println!("area={} / {}", r.area(), r.hello());
for s in [Shape::Circle(1.0), Shape::Square(2.0)] {
println!("{:.2}", area(&s));
}
let v: Vec<i32> = (1..=10).collect();
let even_sq: Vec<i32> = v.iter().filter(|n| *n % 2 == 0).map(|n| n * n).collect();
println!("{even_sq:?} 合計={}", even_sq.iter().sum::<i32>());
}
x=10 y=15 kind=大
area=12 / 3x4 の長方形です
3.14
4.00
[4, 16, 36, 64, 100] 合計=220
| 種類 | 型 | メモ |
|---|---|---|
| 符号付き整数 | i8・i16・i32・i64・i128・isize | 型を書かない整数は i32 |
| 符号なし整数 | u8・u16・u32・u64・u128・usize | 添字は usize |
| 浮動小数点 | f32・f64 | 書かないと f64 |
| 真偽・文字 | bool・char | char は Unicode の1文字(4バイト) |
| 文字列 | String・&str | String は持ち主のある文字列、&str は借りた文字列 |
| まとまり | タプル・配列・Vec・HashMap | Vec は伸び縮みする配列 |
enum の match で場合を書き漏らすと、コンパイルが止まります。Triangle を足して match を直し忘れた例です。
error[E0004]: non-exhaustive patterns: `&Shape::Triangle(_, _)` not covered
--> nomatch.rs:3:11
|
3 | match s {
| ^ pattern `&Shape::Triangle(_, _)` not covered
Go 言語と文法を比べながら読みたい場合は、関連記事「Go言語入門|1.27対応の基本文法を実行結果つきで解説」で扱っています。
所有権・借用とは:コンパイルエラーの原文で理解する
この節では、Rust 入門でいちばんつまずく所有権と借用の決まりと、それに反したときのエラーの読み方が分かります。
所有権の決まりは3つです。 値には持ち主(所有者)が1人だけいる。持ち主がスコープ({ } の範囲)を出ると値は解放される。値を別の変数に渡すと、持ち主が移る(ムーブ)。
ムーブした値は使えない(E0382)
fn main() {
let s1 = String::from("hello");
let s2 = s1; // 持ち主が s1 から s2 へ移る
println!("{s1}, {s2}");
}
error[E0382]: borrow of moved value: `s1`
--> e0382.rs:4:16
|
2 | let s1 = String::from("hello");
| -- move occurs because `s1` has type `String`, which does not implement the `Copy` trait
3 | let s2 = s1;
| -- value moved here
4 | println!("{s1}, {s2}");
| ^^ value borrowed here after move
|
help: consider cloning the value if the performance cost is acceptable
|
3 | let s2 = s1.clone();
| ++++++++
エラーは「どこで移り(value moved here)、どこで使おうとしたか(value borrowed here after move)」を矢印で示します。i32 のような小さな値は Copy を持つため、代入しても移らず、このエラーになりません。
値を関数や変数に渡すとき
let s2 = s1; 持ち主が移り、s1 はもう使えないlen_of(&s1) 貸すだけなので、s1 を使い続けられる。両方に持たせたいなら s1.clone()見分ける問い:「渡したあとも元の変数を使うか」
fn len_of(s: &String) -> usize { s.len() } // & で借りて受け取る
fn main() {
let s1 = String::from("hello");
let n = len_of(&s1); // 貸すだけ
let s2 = s1.clone(); // 複製
println!("{s1}, {s2}, {n}");
}
// 実行結果: hello, hello, 5
借用の決まり(E0502・E0499)
「読み取りの借用(&)は何人でも、書き込みの借用(&mut)は1人だけ、両方は同時に持てない」が借用の決まりです。
// let first = &v[0]; のあとで v.push(4); をした
error[E0502]: cannot borrow `v` as mutable because it is also borrowed as immutable
--> e0502.rs:4:5
|
3 | let first = &v[0];
| - immutable borrow occurs here
4 | v.push(4);
| ^^^^^^^^^ mutable borrow occurs here
5 | println!("{first}");
| ----- immutable borrow later used here
// &mut s を2つ同時に作った
error[E0499]: cannot borrow `s` as mutable more than once at a time
--> e0499.rs:4:13
|
3 | let a = &mut s;
| ------ first mutable borrow occurs here
4 | let b = &mut s;
| ^^^^^^ second mutable borrow occurs here
E0502 は、Vec に要素を足すと中身の置き場所が引っ越すことがあり、first が解放済みの場所を指してしまうのを防いでいます。同じ処理を C++ で書くと、手元の g++ 13.3.0(-Wall -Wextra)は警告なしでコンパイルし、実行すると 1 ではなく 1607754968 と表示されました。直し方は、push を先に済ませてから借りることです。
ぶら下がり参照(E0106)
関数の中で作った値への参照を返そうとすると、値は関数を出るときに解放されるため、コンパイラが止めます。
error[E0106]: missing lifetime specifier
--> e0106.rs:1:16
|
1 | fn dangle() -> &String {
| ^ expected named lifetime parameter
|
= help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from
...
help: instead, you are more likely to want to return an owned value
|
1 - fn dangle() -> &String {
1 + fn dangle() -> String {
ここで出てくる「ライフタイム」は、参照が有効な期間のことです。多くの場合コンパイラが推論し、書く必要があるのは、このような「どこから借りたか分からない」場面です。
Option・Resultとスレッド安全:nullとデータ競合を防ぐ仕組み
この節では、null と例外の代わりに使う Option・Result と、スレッドでデータ競合が起きない理由が、実行結果で分かります。
Option と Result
use std::num::ParseIntError;
fn parse_age(s: &str) -> Result<u32, ParseIntError> {
let n: u32 = s.trim().parse()?; // ? : 失敗ならエラーを呼び出し元へ返す
Ok(n)
}
fn find_user(id: u32) -> Option<&'static str> {
match id {
1 => Some("alice"),
_ => None, // null の代わり
}
}
fn main() {
for s in ["42", "abc", "-1"] {
match parse_age(s) {
Ok(n) => println!("{s:>4} -> Ok({n})"),
Err(e) => println!("{s:>4} -> Err({e})"),
}
}
for id in [1, 2] {
match find_user(id) {
Some(name) => println!("id={id} -> {name}"),
None => println!("id={id} -> 見つかりません"),
}
}
}
42 -> Ok(42)
abc -> Err(invalid digit found in string)
-1 -> Err(invalid digit found in string)
id=1 -> alice
id=2 -> 見つかりません
Option<&str> をそのまま &str として使おうとすると、E0308 になります。Java の NullPointerException のように、実行してから落ちるのではなく、コンパイルの段階で「無い場合」の扱いを求められます。
error[E0308]: mismatched types
--> opt_err.rs:5:22
|
5 | let name: &str = find_user(2);
| ---- ^^^^^^^^^^^^ expected `&str`, found `Option<&str>`
Java で null が原因で落ちる例と見比べるなら、関連記事「NullPointerExceptionの原因と対処法|原因別早見表【Java】」で扱っています。
スレッドとデータ競合(E0373・E0277)
スレッドに変数を貸したまま関数が終わる可能性があると E0373、スレッドの間で安全に渡せない型(参照カウントの Rc)を渡すと E0277 になりました。
error[E0373]: closure may outlive the current function, but it borrows `v`, which is owned by the current function
help: to force the closure to take ownership of `v` (and any other referenced variables), use the `move` keyword
|
4 | let handle = thread::spawn(move || {
error[E0277]: `Rc<Vec<i32>>` cannot be sent between threads safely
= help: within `{closure@rc_thread.rs:6:19: 6:26}`, the trait `Send` is not implemented for `Rc<Vec<i32>>`
スレッドで共有して書き換えるときは、Arc(スレッド安全な参照カウント)と Mutex(排他制御)を組み合わせます。8スレッドで10万回ずつ足すと、毎回 800000 になりました。Mutex を通さずに書き換える書き方は、コンパイルが通りません。
use std::sync::{Arc, Mutex};
use std::thread;
fn main() {
let counter = Arc::new(Mutex::new(0));
let mut handles = vec![];
for _ in 0..8 {
let c = Arc::clone(&counter);
handles.push(thread::spawn(move || {
for _ in 0..100_000 {
*c.lock().unwrap() += 1;
}
}));
}
for h in handles { h.join().unwrap(); }
println!("合計: {}", *counter.lock().unwrap()); // 合計: 800000
}
実行時に止まるもの(パニック)
コンパイルで防げない誤りは、実行時にパニック(安全に止まる)になります。配列の範囲外を読むと、C は何かの値を読んで動き続け、Rust は止まりました。
$ ./idx_c # C(gcc -O0):要素5個の配列の a[10] を読む
a[10] = -914185782
$ echo $?
0
$ ./idx # Rust:同じ処理
thread 'main' (1443) panicked at idx.rs:4:29:
index out of bounds: the len is 5 but the index is 10
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
$ echo $?
101
整数のあふれは、開発用のビルド(cargo build)では attempt to add with overflow のパニックになり、最適化ビルド(--release)では折り返して 0 になりました。Cargo のプロファイルの既定で、overflow-checks が dev は true、release は false だからです。あふれてよい計算は wrapping_add、検出したい計算は checked_add を使います。
Rustのテスト・整形・Lint(cargo test・fmt・clippy)
この節では、Rust に最初から入っているテストの仕組みと、コードの整形・検査の道具が、実行結果で分かります。
単語の出現回数を数えるライブラリ wordfreq を cargo new --lib で作り、3種類のテストを書きました。
use std::collections::HashMap;
/// 空白で区切った単語の出現回数を数える。
///
/// ```
/// let m = wordfreq::count("a b a");
/// assert_eq!(m["a"], 2);
/// ```
pub fn count(text: &str) -> HashMap<String, usize> {
let mut map = HashMap::new();
for w in text.split_whitespace() {
*map.entry(w.to_lowercase()).or_insert(0) += 1;
}
map
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn counts_case_insensitive() {
let m = count("Rust rust RUST go");
assert_eq!(m["rust"], 3);
assert_eq!(m["go"], 1);
}
}
$ cargo test
Running unittests src/lib.rs (target/debug/deps/wordfreq-2bc734e2501f32f3)
running 3 tests
test tests::counts_case_insensitive ... ok
test tests::empty_text ... ok
test tests::top_sorts_by_count_then_word ... ok
test result: ok. 3 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
Running tests/cli_like.rs (target/debug/deps/cli_like-5e57a177c8f7821b)
test top_one_word ... ok
Doc-tests wordfreq
test src/lib.rs - count (line 5) ... ok
- 同じファイルの単体テスト(
#[cfg(test)])、tests/の結合テスト、ドキュメントの中のコード例(Doc-tests)の3つが、cargo test1回で動きました。ドキュメントに書いた例がコードと合わなくなると、テストが失敗して気づけます。 cargo test countsのように名前の一部を渡すと、そのテストだけが動きます(2 filtered outと表示)。
期待値をわざと 2 に変えて失敗させたときの表示です。
test tests::counts_case_insensitive ... FAILED
---- tests::counts_case_insensitive stdout ----
thread 'tests::counts_case_insensitive' (3073) panicked at src/lib.rs:33:9:
assertion `left == right` failed
left: 1
right: 2
test result: FAILED. 2 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
error: test failed, to rerun pass `--lib`
テストの種類の分け方は、関連記事「単体テストと結合テストの違い|pytestの実例と実行結果で比較」で扱っています。
cargo fmt と cargo clippy
わざと崩して書いた1行の関数に、clippy は5つの警告を出しました。
// src/bad.rs
pub fn is_empty_len(v:&Vec<i32>)->bool{ if v.len()==0 {return true;} else {return false;} }
$ cargo clippy
warning: unneeded `return` statement
warning: unneeded `return` statement
warning: writing `&Vec` instead of `&[_]` involves a new object where a slice will do
warning: this if-then-else expression returns a bool literal
warning: length comparison to zero
warning: `wordfreq` (lib) generated 5 warnings (run `cargo clippy --fix --lib -p wordfreq` to apply 4 suggestions)
cargo fmt --check は整形前後の差分を出して終了コード 1 を返し、cargo fmt で整形されました。警告に従うと、関数は次の形になり、clippy の警告は0になりました。
pub fn is_empty_len(v: &[i32]) -> bool {
v.is_empty()
}
エディターは、VS Code・RustRover・Vim/Neovim・Zed などが公式サイトで案内されています。VS Code の保存時の整形などの設定は、関連記事「VS Code settings.jsonおすすめ設定|コピペ用全文と各項目解説」で扱っています。
RustとC・Go・Pythonの速度・メモリ比較(実測)
この節では、同じ処理を4つの言語で書いたときの実行時間・メモリ・実行ファイルの大きさが、手元の計測で分かります。
次の2つの処理を、同じアルゴリズムで書きました。1回空回ししてから5回測り、中央値をとっています。メモリは最大常駐メモリ(maxrss)です。
- ふるい:エラトステネスのふるいで 5,000万以下の素数を数える(答え 3001134)。配列とループの速さを見る。
- 単語数え:500万語(22.9MB)のテキストの単語ごとの出現回数を数え、上位3つを出す。文字列とハッシュ表の速さを見る。
| 言語 | ふるい 時間 | ふるい メモリ | 単語数え 時間 | 単語数え メモリ |
|---|---|---|---|---|
| Rust 1.91.1(-C opt-level=3) | 0.259秒 | 49.8MB | 0.204秒 | 25.5MB |
| C(gcc 13.3.0 -O2) | 0.283秒 | 49.4MB | 0.330秒 | 24.9MB |
| Go 1.24.7 | 0.490秒 | 49.8MB | 0.492秒 | 123.1MB |
| Python 3.13.18 | 14.280秒 | 58.9MB | 1.231秒 | 323.2MB |
| Python(スライス代入で書き直し) | 0.713秒 | 106.7MB | ― | ― |
| Rust の開発用ビルド(最適化なし) | 2.833秒 | 49.8MB | ― | ― |
Rust の単語数えの中心です。テキストを1度読み込み、単語は元の文字列を借りる(&str)ため、単語ごとに文字列を複製していません。
let text = std::fs::read_to_string(path).unwrap();
let mut m: HashMap<&str, usize> = HashMap::new();
for w in text.split_ascii_whitespace() {
*m.entry(w).or_insert(0) += 1;
}
| 言語 | コンパイル時間(単語数え) | 実行ファイル(シンボル削除後) |
|---|---|---|
| Rust | 1.08秒 | 418,680バイト |
| C | 0.11秒 | 14,472バイト |
| Go | 0.63秒(最初の1回は標準ライブラリのキャッシュ作りで 11.77秒) | 1,560,760バイト |
- Rust は C と同じ水準の速さで、Go より速く、素直に書いた Python より大幅に速い結果でした。 ただし Python も、標準の書き方(スライス代入・Counter)に寄せると差は数倍まで縮みました。
- 最適化なしのビルドは約11倍遅くなりました(0.259秒 → 2.833秒)。速さを測る・配るときは
cargo build --releaseを使います。 - Go の単語数えのメモリが大きいのは、
strings.Fieldsが500万個の文字列の一覧を先に作る書き方のためで、言語の限界ではありません。C の単語数えは自作の簡単なハッシュ表で、作り方しだいで結果は変わります。 - Ubuntu の rustc で作った実行ファイルは、標準ライブラリのデバッグ情報が入って約11.7MB でした。
-C strip=symbols(Cargo.toml では[profile.release]にstrip = "symbols")で Hello World が 385,896バイトになりました。 - 2 vCPU の仮想マシンでの値で、Python のふるいは 10.4〜14秒台とぶれました。環境が違えば数値は変わります。
計測で気を付けること(空回し・回数・ばらつき)は、関連記事「ベンチマークの落とし穴8選|JMH・p99・ウォームアップ」で扱っています。
Rustのメリット・デメリットと、向く・向かないの判断表
この節では、Rust を選ぶとよい場面と、他の言語を選ぶほうがよい場面が分かります。
メリット
C並みの速さで、GC の停止がない
メモリの誤り・データ競合をコンパイルで止める
1つの実行ファイルで配れる
cargo・テスト・整形・Lint が公式で揃う
デメリット
所有権・借用・ライフタイムに慣れるまで時間がかかる
コンパイルが遅め(依存1つで最初のビルド 29.4秒)
GUI・スマホの画面づくりの道具はまだ少ない
求人の分野がインフラ・基盤寄りに偏る
| 作りたいもの・状況 | Rust が向くか | 候補になる言語 |
|---|---|---|
| 速さが要る CLI・データ処理 | 向く | Rust・Go・C++ |
| C・C++ の置き換え(安全性を上げたい) | 向く | Rust |
| 遅延の山を避けたいサーバー | 向く | Rust・C++ |
| ブラウザで重い計算(WebAssembly) | 向く | Rust・C++ |
| 一般的な業務システム・Web アプリ | 他の言語でもよい | Java・C#・Go・TypeScript・Python |
| 短期間の試作・データ分析 | 向かない | Python |
| スマホアプリの画面 | 向かない | Swift・Kotlin・Flutter(Dart) |
| チームに経験者がいない・納期が短い | 慎重に | チームが慣れた言語 |
Rustでよくあるエラー・つまずき(原文つき)
この節では、Rust 入門で出会うエラーの原文と、直し方が一覧で分かります。
| エラーの原文(抜粋) | 原因 | 直し方 |
|---|---|---|
E0382 borrow of moved value |
ムーブした変数を使った | & で貸す・.clone() |
E0502 cannot borrow `v` as mutable because it is also borrowed as immutable |
読み取りの借用中に書き換えた | 書き換えを先に済ませる |
E0499 cannot borrow `s` as mutable more than once at a time |
&mut を2つ同時に作った |
使い終えてから次を作る |
E0384 cannot assign twice to immutable variable `x` |
mut なしの変数に再代入 |
let mut x |
E0106 missing lifetime specifier |
関数の中の値の参照を返した | 値そのもの(String)を返す |
E0373 closure may outlive the current function |
スレッドに変数を貸した | move || |
E0277 ... cannot be sent between threads safely |
Rc をスレッドに渡した | Arc(書き換えるなら Mutex も) |
E0004 non-exhaustive patterns |
match の書き漏らし | 場合を足す・_ => |
index out of bounds: the len is 5 but the index is 10 |
範囲外の添字(実行時のパニック) | v.get(i) で Option を受け取る |
could not find `Cargo.toml` in `/dev/shm/t37` or any parent directory |
プロジェクトの外で cargo run | Cargo.toml のあるフォルダーへ移る |
a bin target must be available for `cargo run` |
ライブラリ(--lib)を cargo run した | cargo test で動かすか、bin を作る |
rustc: command not found |
PATH が通っていない | ターミナルを開き直す・PATH を確かめる |
linker `cc` not found |
C のリンカーが無い(手元では別名を指定して再現) | Linux は gcc か clang、Windows は MSVC のビルドツール |
2024 エディションのプロジェクトを 1.85 より前の rustc でビルドしようとしたときも、エディションに対応していない旨のエラーになります。rustc --version で版を確かめ、rustup なら rustup update で上げます。
Rustを学ぶ順番(入門のロードマップ)
この節では、Rust 入門から小さな道具を作れるようになるまでの順番が分かります。
- 1Rust Playground で書いてみるインストールなしで println!・変数・if・for を試す
- 2rustup で入れ、cargo new → cargo runcargo の基本コマンドに慣れる
- 3The Book(日本語版あり)の4章「所有権」まで読むE0382・E0502 を自分で出して直す
- 4struct・enum・match・Option・Resultエラー処理を ? で書けるようにする
- 5Rustlings で小さな問題を解くコマンドラインで、コンパイルエラーを直しながら進む公式の教材
- 6トレイト・ジェネリクス・イテレーターRust By Example でコードを多く読む
- 7小さな CLI を作り、cargo test・clippy を通すこの記事の wordfreq のような道具
- 8目的の分野へWeb は Axum と Tokio、WebAssembly、組み込みは Embedded Book
The Book の日本語版(doc.rust-jp.rs)は、ページの記載では Rust 1.58 以降を前提にした版です。英語版のほうが新しい版に追いついているため、エディションの違いなどで迷ったら英語版も見比べます。
- 1エラーは help: の行まで読む直し方の候補(clone・move・mut)がそのまま書かれていることが多い
- 2分からないエラー番号は rustc --explain誤りの例と直した例が表示される(公式の Compiler Error Index と同じ内容)
- 3最初は clone で逃げてよい動くものを作ってから、借用に直して速くする順番のほうが進みやすい
- 4速さは --release で測る開発用のビルドは手元で約11倍遅かった
よくある質問
Q. Rust言語とは何ですか? A. C・C++ 並みの速さと、メモリの誤りをコンパイル時に止める安全性を両立したプログラミング言語です。GC を使わず、所有権の決まりでメモリを管理します。1.0 は 2015年5月15日に公開されました。
Q. Rustは何と読みますか?ゲームのRustと同じですか? A. 「ラスト」と読みます。同じ名前のサバイバルゲームがありますが、プログラミング言語の Rust とは別のものです。
Q. Rustでできることは何ですか? A. コマンドラインツール、Web サーバー・API、OS やカーネルの部品、ブラウザ、WebAssembly、組み込み、デスクトップアプリ(Tauri)、ゲーム(Bevy)などです。Android・Linux カーネル・AWS の Firecracker などで使われています。
Q. Rustは難しいですか? A. 文法そのものより、所有権・借用に慣れるまでが難しい言語です。ただしエラーメッセージが直し方まで示すため、エラーを1つずつ直しながら覚えられます。C・C++ の経験があると、決まりの理由が分かりやすくなります。
Q. RustとC++はどちらを学ぶべきですか? A. 新しく書くコードで安全性を重視するなら Rust、既存の C++ の資産やゲームエンジン(Unreal Engine など)を扱うなら C++ です。両方の考え方は共通する部分が多く、片方の経験はもう片方でも役に立ちます。
Q. RustとGoの違いは何ですか? A. Go は GC があり、文法が小さく、早く書けることを重視しています。Rust は GC がなく、速さと安全性を型の仕組みで保証します。手元の計測では Rust のほうが速く、メモリも少なくなりましたが、書き上げるまでの時間は Go のほうが短くなりがちです。
Q. Rustのインストールは apt と rustup のどちらがよいですか?
A. 学習や開発には公式の rustup が向いています。版の更新・切り替え・ターゲットの追加ができます。apt の版は遅れることがあり、Ubuntu 24.04 の rustc パッケージは 1.75.0 で、2024 エディションを使えませんでした。
Q. Windowsでインストールできません。 A. rustup の公式ドキュメントによると、Windows では MSVC のビルドツール(Visual Studio の「C++ によるデスクトップ開発」と Windows SDK)が要ります。rustup-init が自動で入れるかを尋ねます。Microsoft Learn は、スマート アプリ コントロールが強制モードの PC では、署名されていないツールチェーンの実行が止められることがある、と注意しています。
Q. Rustのコンパイルが遅いのですが。
A. 依存の多いプロジェクトの最初のビルドは時間がかかります(手元では依存1つ・40クレートで 29.4秒)。2回目以降は変わった部分だけをビルドします。文法と型の検査だけなら、実行ファイルを作らない cargo check が速く済みます。
Q. Rustに将来性はありますか? A. Linux カーネルで実験の段階を終え、Android ではメモリ安全性の脆弱性が大きく減ったと報告され、米国の CISA と NSA もメモリ安全な言語への移行を勧めています。一方で求人はインフラ・基盤・組み込みなどの分野が中心で、件数は求人サイトで確かめるのが確実です。
Q. unsafe とは何ですか?
A. コンパイラの安全性の検査の一部を外す書き方です。OS やハードウェアを直接扱う場面、C のライブラリを呼ぶ場面で使います。unsafe と書いた範囲だけを人が注意して確かめればよい、というのが Rust の考え方です。
まとめ
- Rust は、C・C++ 並みの速さとメモリ安全を両立したコンパイル型の言語。2026年10月29日時点の安定版は 1.99.1、6週間ごとに更新される。
- 公式の入れ方は rustup。Windows は MSVC のビルドツールが要る。Ubuntu の apt は版付きのパッケージ(手元は rustc-1.91)を選ぶと 2024 エディションが使える。
- 所有権・借用の誤りは E0382・E0502・E0499・E0106 などのコンパイルエラーになり、help: の行に直し方まで書かれる。null は Option、失敗は Result で表す。
- 手元の計測では、ふるいで C と同程度(0.26秒)、素直な Python の約55倍の速さ。単語数えのメモリは Python の約13分の1。速さは --release で測る。
- Android・Linux カーネル・AWS Firecracker・Discord などで使われている。学ぶ順番は Playground → cargo → The Book の所有権 → Rustlings → 小さな CLI。
次に読むとよい記事です。Go 言語との書き方の違いは関連記事「Go言語入門|1.27対応の基本文法を実行結果つきで解説」で、計測の注意点は関連記事「ベンチマークの落とし穴8選|JMH・p99・ウォームアップ」で扱っています。
参考・出典
確認日はいずれも 2026年10月29日です。
- Rust 公式「はじめに」:https://rust-lang.org/ja/learn/get-started/
- Rust 公式「Install Rust」:https://www.rust-lang.org/tools/install
- Rust 公式「Learn Rust」(The Book・Rust By Example・Rustlings):https://www.rust-lang.org/learn
- rustup 公式ドキュメント「MSVC prerequisites」:https://rust-lang.github.io/rustup/installation/windows-msvc.html
- Rust Blog「Releases」(1.99.1 ほか各版とエディションの公開日):https://blog.rust-lang.org/releases/
- The Rust Edition Guide「What are editions?」:https://doc.rust-lang.org/edition-guide/editions/index.html
- The Cargo Book「Profiles」:https://doc.rust-lang.org/cargo/reference/profiles.html
- The Rust Programming Language 日本語版:https://doc.rust-jp.rs/book-ja/
- Google「Rust in Android: move fast and fix things」(2025年11月13日):https://blog.google/security/rust-in-android-move-fast-fix-things/
- LWN.net「The (successful) end of the kernel Rust experiment」(2025年12月10日):https://lwn.net/Articles/1049831/
- Discord「Why Discord is switching from Go to Rust」(2020年2月4日):https://discord.com/blog/why-discord-is-switching-from-go-to-rust
- Firecracker 公式サイト:https://firecracker-microvm.github.io/
- Microsoft Learn「Windows での Rust の概要」:https://learn.microsoft.com/ja-jp/windows/dev-environment/rust/overview
- Rust Foundation「About」:https://rustfoundation.org/about/
- Stack Overflow「2025 Developer Survey — Technology」:https://survey.stackoverflow.co/2025/technology/
- CISA「New Guidance Released for Reducing Memory-Related Vulnerabilities」(2025年6月24日):https://www.cisa.gov/news-events/alerts/2025/06/24/new-guidance-released-reducing-memory-related-vulnerabilities
本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。
(記載例)出典:株式会社RJC「Rust言語とは?特徴・できること・入門|所有権エラーと速度を実測」
株式会社RJC ― SI事業・SES事業・AI駆動開発。RJCは一緒に成長を楽しめる会社です。
WE ARE HIRING
RJCで一緒に開発しながら、
成長を楽しみませんか?
RJCは、Web・モバイル・AIを活用した開発プロジェクトで、テックリードやPM・PMOも活躍するシステム開発会社です。会社を知る、待遇を確かめる、話を聞いてみる。気になるところ見てみてください!
- 127日年間休日
- 12時間平均残業時間
- 毎日ガチャ遊びココロも大切にする福利厚生。アマギフなどの賞品ラインナップ!
ほかにも、チケットレストラン、書籍読み放題、2年ごとの慰労報奨(休暇 or 金一封)、11期連続の黒字決算。