Welcome to Tech Athletes | テック・アスリート   Click to listen highlighted text! Welcome to Tech Athletes | テック・アスリート

【2026年最新】Rust完全入門ガイド|インストールから所有権・借用・ライフタイムまで実践コードで徹底解説

Rustとは?なぜ今Rustを学ぶべきか

RustはMozillaが開発したシステムプログラミング言語で、メモリ安全性・速度・並行性を同時に実現します。2015年の正式リリース以来、Stack Overflowの開発者調査で9年連続「最も愛されるプログラミング言語」に選ばれ続けており、LinuxカーネルへのRustコード採用やGoogle・Microsoft・AWSなど大手テック企業での採用が急増しています。

Rustが選ばれる5つの理由

  • メモリ安全性:ガベージコレクタなしでメモリ安全を保証
  • 高パフォーマンス:C/C++と同等の実行速度
  • 並行性の安全:コンパイル時にデータ競合を防止
  • 豊富なエコシステム:Cargo(パッケージマネージャ)による依存管理
  • WebAssembly対応:WebブラウザでもRustコードを実行可能

Rustのインストールと環境構築

Rustのインストールはrustupを使うのが公式推奨です。以下のコマンドを実行します。

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

# インストール確認
rustc --version
cargo --version

Windowsの場合はrustup-init.exeをダウンロードして実行します。VS Codeを使う場合はrust-analyzer拡張機能のインストールを強くお勧めします。

Rustの基本文法

変数とミュータビリティ

Rustでは変数はデフォルトでイミュータブル(不変)です。変更可能にするにはmutキーワードが必要です。

fn main() {
    // イミュータブル変数
    let x = 5;
    println!("x = {}", x);
    
    // ミュータブル変数
    let mut y = 10;
    y += 5;
    println!("y = {}", y);
    
    // 定数(型注釈が必要)
    const MAX_POINTS: u32 = 100_000;
    println!("MAX_POINTS = {}", MAX_POINTS);
}

データ型

fn main() {
    // 整数型
    let a: i32 = -10;   // 符号付き32ビット整数
    let b: u64 = 100;   // 符号なし64ビット整数
    let c: i8 = 127;    // 符号付き8ビット整数
    
    // 浮動小数点型
    let d: f64 = 3.14;
    let e: f32 = 2.71;
    
    // 真偽値
    let is_active: bool = true;
    
    // 文字型(Unicodeスカラー値)
    let ch: char = '日';
    
    // タプル
    let tup: (i32, f64, u8) = (500, 6.4, 1);
    let (x, y, z) = tup;  // デストラクチャリング
    
    // 配列(固定長)
    let arr = [1, 2, 3, 4, 5];
    let first = arr[0];
    
    println!("a={}, b={}, ch={}", a, b, ch);
}

Rustの核心:所有権(Ownership)

Rustの最も重要かつユニークな概念が所有権(Ownership)です。ガベージコレクタを使わずにメモリ安全を実現するための仕組みです。

所有権の3つのルール

  1. Rustの各値は「所有者(owner)」と呼ばれる変数を持つ
  2. 一度に所有者は1つだけ存在できる
  3. 所有者がスコープから外れると、値は自動的に破棄(drop)される
fn main() {
    // s1がString "hello"を所有
    let s1 = String::from("hello");
    
    // s1の所有権がs2に移動(ムーブ)
    let s2 = s1;
    
    // エラー:s1はもう有効でない
    // println!("{}", s1);  // ← コンパイルエラー!
    
    println!("{}", s2);  // OK
    
    // クローン(深いコピー)
    let s3 = s2.clone();
    println!("s2={}, s3={}", s2, s3);  // 両方OK
}

参照と借用(References and Borrowing)

所有権を移動させずに値を使いたい場合は参照(reference)を使います。参照を使うことを「借用(borrowing)」と呼びます。

fn main() {
    let s1 = String::from("hello");
    
    // &s1で参照を渡す(所有権は移動しない)
    let len = calculate_length(&s1);
    
    println!("{}の長さは{}です", s1, len);  // s1はまだ有効
}

fn calculate_length(s: &String) -> usize {
    s.len()
}  // sはここで破棄されるが、所有権がないのでString自体は解放されない
fn main() {
    let mut s = String::from("hello");
    
    // ミュータブル参照
    change(&mut s);
    println!("{}", s);  // "hello, world"
}

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

// 注意:同じスコープ内でミュータブル参照は1つだけ
// let r1 = &mut s;
// let r2 = &mut s;  // ← エラー!

ライフタイム(Lifetimes)

ライフタイムはRustコンパイラが参照の有効期間を追跡するための仕組みです。ダングリングポインタを防ぎます。

// ライフタイム注釈
fn longest<'a>(x: &'a str, y: &'a str) -> &'a str {
    if x.len() > y.len() {
        x
    } else {
        y
    }
}

fn main() {
    let s1 = String::from("long string is long");
    let result;
    {
        let s2 = String::from("xyz");
        result = longest(s1.as_str(), s2.as_str());
        println!("longest: {}", result);
    }
}

構造体とトレイト

// 構造体の定義
#[derive(Debug)]
struct Rectangle {
    width: f64,
    height: f64,
}

// メソッドの実装
impl Rectangle {
    // コンストラクタ(慣例的にnewを使う)
    fn new(width: f64, height: f64) -> Self {
        Rectangle { width, height }
    }
    
    // 面積を計算するメソッド
    fn area(&self) -> f64 {
        self.width * self.height
    }
    
    // 周長を計算するメソッド
    fn perimeter(&self) -> f64 {
        2.0 * (self.width + self.height)
    }
    
    // 正方形かどうか判定
    fn is_square(&self) -> bool {
        self.width == self.height
    }
}

fn main() {
    let rect = Rectangle::new(10.0, 5.0);
    println!("{:?}", rect);
    println!("面積: {}", rect.area());
    println!("周長: {}", rect.perimeter());
    println!("正方形: {}", rect.is_square());
}

トレイト(Trait)

トレイトは他の言語のインターフェースに相当します。共通の振る舞いを定義します。

// トレイトの定義
trait Shape {
    fn area(&self) -> f64;
    fn perimeter(&self) -> f64;
    
    // デフォルト実装
    fn describe(&self) -> String {
        format!("面積: {:.2}, 周長: {:.2}", self.area(), self.perimeter())
    }
}

struct Circle {
    radius: f64,
}

impl Shape for Circle {
    fn area(&self) -> f64 {
        std::f64::consts::PI * self.radius * self.radius
    }
    
    fn perimeter(&self) -> f64 {
        2.0 * std::f64::consts::PI * self.radius
    }
}

fn print_shape_info(shape: &dyn Shape) {
    println!("{}", shape.describe());
}

fn main() {
    let circle = Circle { radius: 5.0 };
    print_shape_info(&circle);
}

エラーハンドリング

Rustは例外機構を持たず、ResultOption型でエラーを扱います。

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

// ? 演算子でエラーを簡潔に伝播
fn read_file(path: &str) -> Result {
    let mut file = File::open(path)?;
    let mut contents = String::new();
    file.read_to_string(&mut contents)?;
    Ok(contents)
}

fn main() {
    match read_file("hello.txt") {
        Ok(contents) => println!("ファイル内容: {}", contents),
        Err(e) => println!("エラー: {}", e),
    }
    
    // unwrap_or_else でエラー時のデフォルト値
    let content = read_file("missing.txt")
        .unwrap_or_else(|_| String::from("ファイルが見つかりません"));
    println!("{}", content);
}

Rustの実用的なプロジェクト:CLIツール作成

実践的なコマンドラインツールを作成してみましょう。ファイルの行数をカウントするツールです。

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

fn main() {
    let args: Vec = env::args().collect();
    
    if args.len() < 2 {
        eprintln!("使い方: {} <ファイルパス>", args[0]);
        process::exit(1);
    }
    
    let filename = &args[1];
    
    match count_lines(filename) {
        Ok(count) => println!("{}: {} 行", filename, count),
        Err(e) => {
            eprintln!("エラー: {}", e);
            process::exit(1);
        }
    }
}

fn count_lines(filename: &str) -> Result {
    let content = fs::read_to_string(filename)?;
    Ok(content.lines().count())
}

Rustのおすすめ学習リソース

  • The Rust Programming Language(通称「The Book」):公式ドキュメント、日本語訳あり
  • Rustlings:小さな演習問題集、ハンズオンで学べる
  • Exercism Rust Track:実践的な課題で学ぶ
  • Zero To Production In Rust:WebアプリのバックエンドをRustで構築

まとめ

Rustは学習曲線が急ですが、所有権・借用・ライフタイムという概念を理解すれば、メモリ安全で高性能なシステムプログラミングが可能になります。エンジニアとしてのスキルセットにRustを加えることで、将来的なキャリアの幅も大きく広がります。まずは公式ドキュメントと小さなCLIツール作成から始めてみましょう!

投稿者 kasata

IT企業でエンジニアとして勤務後、テクノロジー情報メディア「Tech Athletes(テック・アスリート)」を運営。プログラミング、クラウドインフラ(AWS/GCP/Azure)、AI活用、Webサービス開発を専門とする。エンジニア・ビジネスパーソン向けに、実際に使ってみた経験をもとに信頼できる技術情報を発信中。資格:AWS認定ソリューションアーキテクト、Python 3 エンジニア認定試験合格。

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

Click to listen highlighted text!