← Rust言語ページに戻る
🦀

Rust言語のサンプルコード

文法解説で学んだ内容を使い、段階的に難易度が上がる3つの実践的なサンプルプログラムを紹介します。実際にRustのコンパイラ(rustcやCargo)で動かしながら読むと理解が深まります。

サンプル1:構造体とimplを使った在庫管理

structimplVec、所有権・借用の基本を組み合わせた小規模プログラムです。 addメソッドは&mut selfで自身を可変借用し、内部のVecに新しい要素を追加します。 totalメソッドは&selfで不変借用のみ行い、イテレータのmapsumで合計を計算します。

SAMPLE PROGRAM
struct Item {
    name: String,
    qty: u32,
    price: u32,
}

struct Inventory {
    items: Vec,
}

impl Inventory {
    fn new() -> Self {
        Inventory { items: Vec::new() }
    }

    // &mut selfで自身を可変借用し、新しい商品を追加する
    fn add(&mut self, name: &str, qty: u32, price: u32) {
        self.items.push(Item {
            name: name.to_string(),
            qty,
            price,
        });
    }

    // 合計在庫数(&selfのみで計算できる読み取り専用処理)
    fn total_qty(&self) -> u32 {
        self.items.iter().map(|item| item.qty).sum()
    }

    // 在庫金額の合計
    fn total_value(&self) -> u32 {
        self.items.iter().map(|item| item.qty * item.price).sum()
    }

    // 在庫が少ない商品を探す(Option<&Item>を返す=見つからない可能性を型で表現)
    fn find_low_stock(&self, threshold: u32) -> Option<&Item> {
        self.items.iter().find(|item| item.qty < threshold)
    }
}

fn main() {
    let mut inv = Inventory::new();
    inv.add("ノート", 10, 120);
    inv.add("消しゴム", 3, 80);
    inv.add("鉛筆", 25, 50);

    println!("合計在庫数: {}", inv.total_qty());
    println!("在庫金額合計: {}円", inv.total_value());

    match inv.find_low_stock(5) {
        Some(item) => println!("在庫少: {}(残り{}個)", item.name, item.qty),
        None => println!("在庫が少ない商品はありません"),
    }
}

サンプル2:クイックソートの実装(探索・整列アルゴリズム)

配列を「基準値(ピボット)より小さいグループ」と「大きいグループ」に分割し、それぞれを再帰的にソートするクイックソートを実装します。 平均計算量はO(n log n)ですが、ピボットの選び方が悪いと最悪計算量はO(n²)になる点も押さえておきましょう。 所有権の都合上、ここでは新しいVecを組み立てて返す関数型スタイルで実装しています。

SAMPLE PROGRAM
// クイックソート:平均計算量 O(n log n)、最悪計算量 O(n^2)
fn quick_sort(arr: &[i32]) -> Vec {
    if arr.len() <= 1 {
        return arr.to_vec(); // 要素が0か1個ならそのまま返す(再帰の終了条件)
    }

    let pivot = arr[arr.len() / 2]; // ピボットとして中央の要素を選ぶ

    let less: Vec = arr.iter().filter(|&&x| x < pivot).copied().collect();
    let equal: Vec = arr.iter().filter(|&&x| x == pivot).copied().collect();
    let greater: Vec = arr.iter().filter(|&&x| x > pivot).copied().collect();

    // less と greater をそれぞれ再帰的にソートしてから結合する
    let mut result = quick_sort(&less);
    result.extend(equal);
    result.extend(quick_sort(&greater));
    result
}

// 線形探索:計算量 O(n)。ソートされていない配列でも使える
fn linear_search(arr: &[i32], target: i32) -> Option {
    for (i, &value) in arr.iter().enumerate() {
        if value == target {
            return Some(i);
        }
    }
    None
}

fn main() {
    let data = [5, 2, 9, 1, 5, 6, 3];

    let sorted = quick_sort(&data);
    println!("ソート結果: {:?}", sorted); // [1, 2, 3, 5, 5, 6, 9]

    match linear_search(&data, 9) {
        Some(idx) => println!("9はインデックス{}にあります", idx),
        None => println!("見つかりませんでした"),
    }
}

サンプル3:Result型を使ったエラーハンドリング(設定値の検証)

複数のバリデーション処理をResult<T, E>?演算子でつなぎ、失敗した時点で即座にエラーを呼び出し元へ伝播させるパターンです。 独自のエラー型enum ConfigErrorを定義し、matchで種類ごとに異なるメッセージを表示します。例外機構を持たないRustならではの、型で表現するエラー処理の典型例です。

SAMPLE PROGRAM
#[derive(Debug)]
enum ConfigError {
    OutOfRange(i32),
    Empty,
}

struct Config {
    name: String,
    max_users: i32,
}

// 名前が空でないかを検証する
fn validate_name(name: &str) -> Result {
    if name.trim().is_empty() {
        return Err(ConfigError::Empty);
    }
    Ok(name.to_string())
}

// 値が範囲内かを検証する
fn validate_max_users(value: i32) -> Result {
    if value < 1 || value > 1000 {
        return Err(ConfigError::OutOfRange(value));
    }
    Ok(value)
}

// ?演算子で複数のResultを連結し、どこかで失敗したら即座にErrを返す
fn build_config(name: &str, max_users: i32) -> Result {
    let name = validate_name(name)?;
    let max_users = validate_max_users(max_users)?;
    Ok(Config { name, max_users })
}

fn main() {
    let inputs = [("サーバーA", 50), ("", 10), ("サーバーB", 5000)];

    for (name, max_users) in inputs {
        match build_config(name, max_users) {
            Ok(config) => {
                println!("OK: {} (max_users={})", config.name, config.max_users)
            }
            Err(ConfigError::Empty) => println!("エラー: 名前が空です"),
            Err(ConfigError::OutOfRange(v)) => {
                println!("エラー: max_usersが範囲外です(値: {})", v)
            }
        }
    }
}

理解度チェッククイズへ進む →