あっぽログ
← 記事一覧に戻る

RustのStructを使いこなす:フィールド・メソッド・関連関数を徹底解説

構造体(Struct)とは?

Rustの**構造体(Struct)**は、複数の値をひとつのまとまりとして扱うためのデータ型です。たとえば「ユーザー情報」を表すときに、名前・年齢・メールアドレスをバラバラの変数で管理するより、構造体にまとめると読みやすく扱いやすいコードになります。

他の言語でいえば、JavaやPHPの「クラス」に近い概念ですが、Rustの構造体はデータの保持に特化しており、振る舞い(メソッド)はimplブロックで別途定義する点が特徴です。


基本的な構造体の定義と生成

structキーワードを使って構造体を定義します。

struct User {
    name: String,
    age: u32,
    email: String,
}

fn main() {
    let user = User {
        name: String::from("Alice"),
        age: 30,
        email: String::from("alice@example.com"),
    };

    println!("名前: {}", user.name);
    println!("年齢: {}", user.age);
}

フィールドへのアクセスはドット記法(.)を使います。

ミュータブルな構造体

構造体のフィールドを変更したい場合は、変数自体をmutで宣言します。Rustでは構造体全体がミュータブルになる点に注意してください(個別フィールドだけをミュータブルにすることはできません)。

fn main() {
    let mut user = User {
        name: String::from("Bob"),
        age: 25,
        email: String::from("bob@example.com"),
    };

    user.age = 26; // フィールドを更新
    println!("誕生日!年齢: {}", user.age);
}

フィールド省略記法とストラクト更新記法

変数名とフィールド名が同じ場合、省略して書けます。また、一部のフィールドだけ変えて新しい構造体を作る「ストラクト更新記法」も便利です。

fn create_user(name: String, email: String) -> User {
    User {
        name,   // 変数名と同じなので省略可
        email,
        age: 0,
    }
}

fn main() {
    let user1 = create_user(String::from("Carol"), String::from("carol@example.com"));

    // user1をベースにageだけ変えた新しいUser
    let user2 = User {
        age: 20,
        ..user1  // 残りのフィールドをuser1からコピー
    };

    println!("名前: {}, 年齢: {}", user2.name, user2.age);
}

⚠️ ..user1を使うとuser1のString型フィールド(nameemail)の所有権が移動するため、その後user1は使えなくなります。


implブロックでメソッドを追加する

構造体に振る舞いを持たせるにはimplブロックを使います。

struct Rectangle {
    width: f64,
    height: f64,
}

impl Rectangle {
    // メソッド:第一引数が &self
    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 {
        width: 10.0,
        height: 5.0,
    };

    println!("面積: {}", rect.area());
    println!("周囲の長さ: {}", rect.perimeter());
    println!("正方形?: {}", rect.is_square());
}

&selfは「この構造体への参照」を意味します。値の読み取りだけなら&self、変更が必要なら&mut selfを使います。

フィールドを変更するメソッド

impl Rectangle {
    fn scale(&mut self, factor: f64) {
        self.width *= factor;
        self.height *= factor;
    }
}

fn main() {
    let mut rect = Rectangle { width: 4.0, height: 3.0 };
    rect.scale(2.0);
    println!("拡大後: {}x{}", rect.width, rect.height); // 8x6
}

関連関数(コンストラクタパターン)

selfを引数に取らない関数を関連関数と呼びます。呼び出しには::を使い、Rustでは慣習的にnewという名前のコンストラクタを定義することが多いです。

impl Rectangle {
    // 関連関数(コンストラクタ)
    fn new(width: f64, height: f64) -> Self {
        Rectangle { width, height }
    }

    fn square(size: f64) -> Self {
        Rectangle { width: size, height: size }
    }
}

fn main() {
    let rect = Rectangle::new(8.0, 6.0);
    let sq = Rectangle::square(5.0);

    println!("長方形の面積: {}", rect.area());
    println!("正方形の面積: {}", sq.area());
}

タプル構造体

フィールド名を省略したい場合はタプル構造体が使えます。

struct Point(f64, f64);
struct Color(u8, u8, u8);

fn main() {
    let origin = Point(0.0, 0.0);
    let red = Color(255, 0, 0);

    println!("座標: ({}, {})", origin.0, origin.1);
    println!("赤: R={}, G={}, B={}", red.0, red.1, red.2);
}

フィールドへのアクセスはインデックス(.0, .1...)で行います。


デバッグ出力を使う(#[derive(Debug)])

開発中に構造体の内容を丸ごと出力したいときは、#[derive(Debug)]を付けて{:?}で表示できます。

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

fn main() {
    let user = User { name: String::from("Dave"), age: 28 };
    println!("{:?}", user);
    println!("{:#?}", user); // 見やすい整形表示
}

まとめ

機能書き方
構造体の定義struct 名前 { フィールド: 型 }
インスタンス生成名前 { フィールド: 値 }
メソッド定義implブロック内にfn メソッド名(&self)
関連関数implブロック内にfn 関数名()
タプル構造体struct 名前(型, 型)
デバッグ出力#[derive(Debug)] + {:?}

Rustの構造体はシンプルながら非常に強力です。implブロックでメソッドを追加し、deriveマクロで便利な機能を自動実装することで、読みやすく安全なコードを書くことができます。まずは小さな構造体を自分で定義して、実際に動かしてみましょう!

← 記事一覧に戻る