Rust入門ガイド2026 — なぜ今Rustを学ぶべきなのか


はじめに

2026年現在、Rustは最も注目されているプログラミング言語の一つです。Stack Overflow Developer Surveyでは7年連続で「最も愛されている言語」に選ばれ、MicrosoftやAmazon、Googleなどの大手企業も積極的に採用しています。

本記事では、Rustの基礎から実践的な使い方まで、初心者にもわかりやすく解説します。

なぜ今Rustを学ぶべきなのか

1. メモリ安全性とパフォーマンスの両立

従来、プログラミング言語は「安全性」と「パフォーマンス」のトレードオフがありました。

  • C/C++: 高速だがメモリ安全性の問題
  • Python/JavaScript: 安全だが実行速度が遅い

Rustはコンパイル時にメモリ安全性を保証しながら、C/C++並みの実行速度を実現します。

2. 業界での採用拡大

2026年現在、以下のような分野でRustの採用が進んでいます。

  • システムプログラミング: Linux Kernel、Windows、Android
  • Web開発: Actix、Rocket、Axumなどのフレームワーク
  • WebAssembly: 高速なブラウザアプリケーション
  • 暗号通貨・ブロックチェーン: Solana、Polkadot
  • 組み込みシステム: IoTデバイス、ロボティクス
  • クラウドインフラ: AWS Lambda、Cloudflare Workers

3. 優れた開発者体験

  • Cargo: 強力なパッケージマネージャー&ビルドツール
  • rustfmt: 統一されたコードフォーマット
  • Clippy: 高度なLinter
  • 充実したドキュメント: 公式ドキュメントが非常に詳細

4. 将来性の高さ

  • GitHub上でのスター数・コントリビューター数が急増
  • 求人市場での需要が年々増加
  • 多くの企業が「次世代の主力言語」として位置づけ

Rustのインストール

rustupを使ったインストール

Rustの公式インストーラーrustupを使うのが最も簡単です。

macOS / Linux:

curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh

Windows:

https://rustup.rs/ からインストーラーをダウンロードして実行。

インストールの確認

rustc --version
cargo --version

正常にインストールされていれば、バージョン情報が表示されます。

rustc 1.85.0 (2026-02-04)
cargo 1.85.0 (2026-02-04)

エディタのセットアップ

VS Code (推奨):

  • 拡張機能「rust-analyzer」をインストール
  • 自動補完、エラー表示、リファクタリング機能が利用可能

その他のエディタ:

  • IntelliJ IDEA: IntelliJ Rustプラグイン
  • Vim/Neovim: rust.vim + coc-rust-analyzer
  • Emacs: rust-mode

Rustの基本文法

Hello, World!

fn main() {
    println!("Hello, World!");
}

実行方法:

# ファイルに保存
rustc hello.rs
./hello

または、Cargoを使う:

cargo new hello_world
cd hello_world
cargo run

変数とデータ型

不変変数(デフォルト):

let x = 5; // 不変
// x = 6; // エラー: 再代入不可

可変変数:

let mut y = 10;
y = 20; // OK

データ型:

// 整数
let a: i32 = 42; // 32ビット符号付き整数
let b: u64 = 100; // 64ビット符号なし整数

// 浮動小数点
let f: f64 = 3.14;

// 真偽値
let flag: bool = true;

// 文字
let c: char = 'あ';

// 文字列
let s: &str = "Hello"; // 文字列スライス
let string: String = String::from("World"); // 所有された文字列

関数

fn add(x: i32, y: i32) -> i32 {
    x + y // 最後の式が戻り値(セミコロンなし)
}

fn main() {
    let result = add(3, 5);
    println!("Result: {}", result);
}

制御構文

if式:

let number = 7;

if number < 5 {
    println!("小さい");
} else if number < 10 {
    println!("中くらい");
} else {
    println!("大きい");
}

// if式は値を返せる
let result = if number % 2 == 0 { "偶数" } else { "奇数" };

ループ:

// loop
let mut counter = 0;
loop {
    counter += 1;
    if counter == 10 {
        break;
    }
}

// while
let mut n = 3;
while n != 0 {
    println!("{}", n);
    n -= 1;
}

// for
for i in 1..=5 {
    println!("{}", i);
}

let arr = [10, 20, 30];
for element in arr.iter() {
    println!("{}", element);
}

コレクション

Vector(動的配列):

let mut vec = Vec::new();
vec.push(1);
vec.push(2);
vec.push(3);

// マクロを使った初期化
let vec2 = vec![1, 2, 3];

// アクセス
println!("{}", vec[0]); // パニックの可能性
println!("{:?}", vec.get(0)); // Optionを返す(安全)

HashMap:

use std::collections::HashMap;

let mut scores = HashMap::new();
scores.insert("Alice", 100);
scores.insert("Bob", 85);

// 取得
match scores.get("Alice") {
    Some(&score) => println!("Alice: {}", score),
    None => println!("見つかりません"),
}

Rustの核心概念

所有権(Ownership)

Rustの最も重要な概念です。メモリ管理をガベージコレクションなしで実現します。

所有権のルール:

  1. 各値には所有者が1つだけ存在する
  2. 所有者がスコープを抜けると、値は破棄される
  3. 値の所有権は移動(move)できる
fn main() {
    let s1 = String::from("hello");
    let s2 = s1; // 所有権がs2に移動

    // println!("{}", s1); // エラー: s1はもう使えない
    println!("{}", s2); // OK
}

関数と所有権:

fn take_ownership(s: String) {
    println!("{}", s);
} // sがドロップされる

fn main() {
    let s = String::from("hello");
    take_ownership(s);
    // println!("{}", s); // エラー: 所有権が移動済み
}

所有権を返す:

fn give_ownership() -> String {
    String::from("hello")
}

fn take_and_give_back(s: String) -> String {
    s
}

fn main() {
    let s1 = give_ownership();
    let s2 = String::from("world");
    let s3 = take_and_give_back(s2);

    println!("{} {}", s1, s3);
}

借用(Borrowing)

所有権を移動させずに値を参照する仕組みです。

不変参照:

fn calculate_length(s: &String) -> usize {
    s.len()
} // sは参照なので所有権はない

fn main() {
    let s1 = String::from("hello");
    let len = calculate_length(&s1);
    println!("'{}' の長さは {}", s1, len); // s1はまだ使える
}

可変参照:

fn append_world(s: &mut String) {
    s.push_str(", world");
}

fn main() {
    let mut s = String::from("hello");
    append_world(&mut s);
    println!("{}", s); // "hello, world"
}

借用のルール:

  1. 任意の時点で、1つの可変参照 または 複数の不変参照のいずれか
  2. 参照は常に有効でなければならない
fn main() {
    let mut s = String::from("hello");

    let r1 = &s; // OK
    let r2 = &s; // OK
    // let r3 = &mut s; // エラー: 不変参照がある間は可変参照を作れない

    println!("{} {}", r1, r2);

    let r3 = &mut s; // OK(r1, r2はもう使われない)
    r3.push_str("!");
}

ライフタイム(Lifetime)

参照が有効な期間を明示する仕組みです。

基本的なライフタイム:

fn longest<'a>(x: &'a str, y: &'a str) -> &'a str {
    if x.len() > y.len() {
        x
    } else {
        y
    }
}

fn main() {
    let string1 = String::from("long string");
    let string2 = String::from("short");

    let result = longest(string1.as_str(), string2.as_str());
    println!("最長: {}", result);
}

構造体のライフタイム:

struct ImportantExcerpt<'a> {
    part: &'a str,
}

fn main() {
    let novel = String::from("Call me Ishmael. Some years ago...");
    let first_sentence = novel.split('.').next().expect("Could not find a '.'");

    let excerpt = ImportantExcerpt {
        part: first_sentence,
    };

    println!("{}", excerpt.part);
}

ライフタイム省略規則:

多くの場合、Rustコンパイラがライフタイムを推論してくれます。

// これは
fn first_word(s: &str) -> &str {
    &s[..1]
}

// 実際にはこう解釈される
fn first_word<'a>(s: &'a str) -> &'a str {
    &s[..1]
}

構造体とEnum

構造体(Struct)

struct User {
    username: String,
    email: String,
    active: bool,
    sign_in_count: u64,
}

impl User {
    // 関連関数(メソッド)
    fn new(username: String, email: String) -> User {
        User {
            username,
            email,
            active: true,
            sign_in_count: 1,
        }
    }

    // メソッド
    fn deactivate(&mut self) {
        self.active = false;
    }

    fn is_active(&self) -> bool {
        self.active
    }
}

fn main() {
    let mut user = User::new(
        String::from("alice"),
        String::from("alice@example.com")
    );

    println!("Active: {}", user.is_active());
    user.deactivate();
    println!("Active: {}", user.is_active());
}

タプル構造体:

struct Color(i32, i32, i32);
struct Point(i32, i32, i32);

let black = Color(0, 0, 0);
let origin = Point(0, 0, 0);

Enum(列挙型)

enum IpAddr {
    V4(u8, u8, u8, u8),
    V6(String),
}

let home = IpAddr::V4(127, 0, 0, 1);
let loopback = IpAddr::V6(String::from("::1"));

Option型:

Rustにはnullがありません。代わりにOptionを使います。

enum Option<T> {
    Some(T),
    None,
}

fn divide(x: f64, y: f64) -> Option<f64> {
    if y == 0.0 {
        None
    } else {
        Some(x / y)
    }
}

fn main() {
    match divide(10.0, 2.0) {
        Some(result) => println!("結果: {}", result),
        None => println!("ゼロ除算エラー"),
    }
}

Result型:

エラーハンドリングに使います。

use std::fs::File;
use std::io::ErrorKind;

fn main() {
    let f = File::open("hello.txt");

    let f = match f {
        Ok(file) => file,
        Err(error) => match error.kind() {
            ErrorKind::NotFound => match File::create("hello.txt") {
                Ok(fc) => fc,
                Err(e) => panic!("ファイル作成エラー: {:?}", e),
            },
            other_error => panic!("ファイルオープンエラー: {:?}", other_error),
        },
    };
}

?演算子:

エラーハンドリングを簡潔に書けます。

use std::fs::File;
use std::io::{self, Read};

fn read_username_from_file() -> Result<String, io::Error> {
    let mut f = File::open("username.txt")?;
    let mut s = String::new();
    f.read_to_string(&mut s)?;
    Ok(s)
}

トレイト(Trait)

トレイトはインターフェースのようなものです。

trait Summary {
    fn summarize(&self) -> String;
}

struct Article {
    title: String,
    content: String,
}

impl Summary for Article {
    fn summarize(&self) -> String {
        format!("{}: {}", self.title, self.content)
    }
}

struct Tweet {
    username: String,
    text: String,
}

impl Summary for Tweet {
    fn summarize(&self) -> String {
        format!("@{}: {}", self.username, self.text)
    }
}

fn notify(item: &impl Summary) {
    println!("速報: {}", item.summarize());
}

fn main() {
    let article = Article {
        title: String::from("Rust入門"),
        content: String::from("Rustを学ぼう"),
    };

    notify(&article);
}

トレイト境界:

fn largest<T: PartialOrd + Copy>(list: &[T]) -> T {
    let mut largest = list[0];

    for &item in list.iter() {
        if item > largest {
            largest = item;
        }
    }

    largest
}

fn main() {
    let numbers = vec![34, 50, 25, 100, 65];
    println!("最大値: {}", largest(&numbers));
}

デフォルト実装:

trait Summary {
    fn summarize(&self) -> String {
        String::from("(続きを読む...)")
    }
}

struct NewsArticle {
    headline: String,
}

impl Summary for NewsArticle {}

fn main() {
    let article = NewsArticle {
        headline: String::from("ニュース"),
    };
    println!("{}", article.summarize()); // デフォルト実装が使われる
}

Cargoとパッケージ管理

Cargoの基本コマンド

# 新規プロジェクト作成
cargo new my_project
cd my_project

# ビルド(デバッグビルド)
cargo build

# リリースビルド(最適化)
cargo build --release

# 実行
cargo run

# テスト実行
cargo test

# ドキュメント生成
cargo doc --open

# 依存関係の更新
cargo update

# コードチェック(ビルドより高速)
cargo check

Cargo.tomlの構造

[package]
name = "my_project"
version = "0.1.0"
edition = "2021"

[dependencies]
serde = { version = "1.0", features = ["derive"] }
tokio = { version = "1.35", features = ["full"] }
reqwest = "0.11"

[dev-dependencies]
mockall = "0.12"

[profile.release]
opt-level = 3
lto = true

crates.ioからの依存関係追加

# cargo addコマンドを使う(cargo-editが必要)
cargo install cargo-edit
cargo add serde
cargo add tokio --features full

# または手動でCargo.tomlに追記してcargo build

ワークスペース

複数のクレートを1つのプロジェクトで管理できます。

# ルートのCargo.toml
[workspace]
members = [
    "frontend",
    "backend",
    "common",
]

実践例:CLIツール作成

簡単なテキスト検索ツール「minigrep」を作ります。

Cargo.toml:

[package]
name = "minigrep"
version = "0.1.0"
edition = "2021"

src/main.rs:

use std::env;
use std::fs;
use std::process;

fn main() {
    let args: Vec<String> = env::args().collect();

    if args.len() < 3 {
        eprintln!("使い方: minigrep <検索文字列> <ファイル名>");
        process::exit(1);
    }

    let query = &args[1];
    let filename = &args[2];

    let contents = fs::read_to_string(filename)
        .unwrap_or_else(|err| {
            eprintln!("ファイル読み込みエラー: {}", err);
            process::exit(1);
        });

    for line in search(query, &contents) {
        println!("{}", line);
    }
}

fn search<'a>(query: &str, contents: &'a str) -> Vec<&'a str> {
    let mut results = Vec::new();

    for line in contents.lines() {
        if line.contains(query) {
            results.push(line);
        }
    }

    results
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn one_result() {
        let query = "duct";
        let contents = "\
Rust:
safe, fast, productive.
Pick three.";

        assert_eq!(vec!["safe, fast, productive."], search(query, contents));
    }
}

実行:

cargo run -- rust sample.txt

WebAssemblyとRust

RustはWebAssemblyの第一級サポート言語です。

wasm-packのインストール

curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh

プロジェクト作成

cargo install cargo-generate
cargo generate --git https://github.com/rustwasm/wasm-pack-template

src/lib.rs:

use wasm_bindgen::prelude::*;

#[wasm_bindgen]
pub fn greet(name: &str) -> String {
    format!("Hello, {}!", name)
}

#[wasm_bindgen]
pub fn fibonacci(n: u32) -> u32 {
    match n {
        0 => 0,
        1 => 1,
        _ => fibonacci(n - 1) + fibonacci(n - 2),
    }
}

ビルド

wasm-pack build --target web

HTMLから使用

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>Rust + Wasm</title>
</head>
<body>
    <script type="module">
        import init, { greet, fibonacci } from './pkg/my_project.js';

        async function run() {
            await init();

            console.log(greet('World'));
            console.log('fib(10) =', fibonacci(10));
        }

        run();
    </script>
</body>
</html>

Web開発フレームワーク

Actix-web(高速なWebフレームワーク)

[dependencies]
actix-web = "4"
tokio = { version = "1", features = ["full"] }
serde = { version = "1", features = ["derive"] }
use actix_web::{get, post, web, App, HttpResponse, HttpServer, Responder};
use serde::{Deserialize, Serialize};

#[derive(Serialize, Deserialize)]
struct User {
    name: String,
    age: u32,
}

#[get("/")]
async fn index() -> impl Responder {
    HttpResponse::Ok().body("Hello, World!")
}

#[get("/users/{id}")]
async fn get_user(path: web::Path<u32>) -> impl Responder {
    let user = User {
        name: format!("User {}", path),
        age: 25,
    };
    HttpResponse::Ok().json(user)
}

#[post("/users")]
async fn create_user(user: web::Json<User>) -> impl Responder {
    HttpResponse::Created().json(user.0)
}

#[actix_web::main]
async fn main() -> std::io::Result<()> {
    HttpServer::new(|| {
        App::new()
            .service(index)
            .service(get_user)
            .service(create_user)
    })
    .bind(("127.0.0.1", 8080))?
    .run()
    .await
}

Axum(軽量でモダンなフレームワーク)

[dependencies]
axum = "0.7"
tokio = { version = "1", features = ["full"] }
serde = { version = "1", features = ["derive"] }
use axum::{
    routing::{get, post},
    Json, Router,
};
use serde::{Deserialize, Serialize};

#[derive(Serialize, Deserialize)]
struct User {
    name: String,
    age: u32,
}

async fn root() -> &'static str {
    "Hello, World!"
}

async fn create_user(Json(payload): Json<User>) -> Json<User> {
    Json(payload)
}

#[tokio::main]
async fn main() {
    let app = Router::new()
        .route("/", get(root))
        .route("/users", post(create_user));

    let listener = tokio::net::TcpListener::bind("127.0.0.1:3000")
        .await
        .unwrap();

    axum::serve(listener, app).await.unwrap();
}

非同期プログラミング

Rustの非同期処理はasync/await構文を使います。

use tokio::time::{sleep, Duration};

async fn say_hello() {
    println!("Hello");
    sleep(Duration::from_secs(1)).await;
    println!("World");
}

async fn fetch_data(url: &str) -> Result<String, reqwest::Error> {
    let response = reqwest::get(url).await?;
    let body = response.text().await?;
    Ok(body)
}

#[tokio::main]
async fn main() {
    say_hello().await;

    match fetch_data("https://api.example.com/data").await {
        Ok(data) => println!("Data: {}", data),
        Err(e) => eprintln!("Error: {}", e),
    }
}

複数のタスクを並列実行:

use tokio::join;

#[tokio::main]
async fn main() {
    let task1 = async {
        sleep(Duration::from_secs(1)).await;
        "Task 1"
    };

    let task2 = async {
        sleep(Duration::from_secs(2)).await;
        "Task 2"
    };

    let (result1, result2) = join!(task1, task2);
    println!("{}, {}", result1, result2);
}

エコシステムと主要クレート

ユーティリティ

  • serde: シリアライゼーション・デシリアライゼーション
  • clap: CLIパーサー
  • regex: 正規表現
  • chrono: 日時処理
  • uuid: UUID生成
  • rand: 乱数生成

Web開発

  • actix-web: 高速なWebフレームワーク
  • axum: モダンなWebフレームワーク
  • rocket: 使いやすいWebフレームワーク
  • reqwest: HTTPクライアント
  • hyper: 低レベルHTTPライブラリ

データベース

  • sqlx: 非同期SQLライブラリ
  • diesel: ORMライブラリ
  • tokio-postgres: PostgreSQLクライアント
  • redis: Redisクライアント

非同期処理

  • tokio: 最も人気のある非同期ランタイム
  • async-std: 標準ライブラリ風の非同期ランタイム
  • futures: Futureトレイトとユーティリティ

テスト

  • mockall: モックライブラリ
  • proptest: プロパティベーステスト
  • criterion: ベンチマーク

ベストプラクティス

1. エラーハンドリング

unwrap()は本番コードでは避け、適切なエラーハンドリングを。

// 悪い例
let file = File::open("config.txt").unwrap();

// 良い例
let file = File::open("config.txt")
    .map_err(|e| format!("設定ファイル読み込みエラー: {}", e))?;

2. クローンを避ける

不必要なclone()は避け、参照を活用。

// 悪い例
fn process(data: Vec<i32>) {
    let copy = data.clone();
    // ...
}

// 良い例
fn process(data: &[i32]) {
    // ...
}

3. イテレータの活用

ループよりイテレータの方が効率的で読みやすい。

// 悪い例
let mut sum = 0;
for i in 0..10 {
    sum += i;
}

// 良い例
let sum: i32 = (0..10).sum();

4. Clippyの活用

rustup component add clippy
cargo clippy

Clippyは多くのアンチパターンを検出してくれます。

5. テストの作成

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_add() {
        assert_eq!(add(2, 3), 5);
    }

    #[test]
    #[should_panic]
    fn test_divide_by_zero() {
        divide(10, 0);
    }
}

学習リソース

公式ドキュメント

オンラインコース

  • Rustlings: インタラクティブな練習問題
  • Exercism Rust Track: 実践的な課題
  • Udemy: Rust入門コース多数

コミュニティ

まとめ

Rustは学習曲線が急ですが、その投資に見合う価値があります。

Rustを学ぶメリット:

  1. メモリ安全性: バグの大部分をコンパイル時に検出
  2. 高性能: C/C++並みの実行速度
  3. 並行処理の安全性: データ競合をコンパイル時に防止
  4. 優れたツール: Cargo、rustfmt、Clippy
  5. 将来性: 業界での採用が急速に拡大

次のステップ:

  1. The Bookを最後まで読む
  2. 小さなCLIツールを作る
  3. WebアプリケーションやAPIを作る
  4. 既存のRustプロジェクトにコントリビュート
  5. 自分のライブラリをcrates.ioに公開

2026年、Rustはシステムプログラミングだけでなく、Web開発、CLI、WebAssembly、組み込みなど幅広い分野で使われています。今こそRustを学び始める絶好のタイミングです。

Happy Rusting!