Moveの型システムは、カスタムタイプを定義する際にその真価を発揮します。ユーザー定義型は、アプリケーションの具体的なニーズに合わせてカスタム調整することができます。これはデータレベルだけでなく、その振る舞いにおいてもです。このセクションでは、構造体の定義とその使用方法を紹介します。

構造体 (Struct)

カスタムタイプを定義するには、struct キーワードの後にタイプの名前を続けて使用します。名前の後には、構造体のフィールドを定義できます。各フィールドは field_name: field_type の構文で定義されます。フィールド定義はコンマで区切られなければなりません。フィールドは他の構造体を含む任意のタイプが可能です。

Moveは再帰的な構造体をサポートしていないため、構造体が自身をフィールドとして含むことはできません。

/// アーティストを表す構造体
public struct Artist {
    /// アーティストの名前
    name: String,
}

/// 音楽レコードを表す構造体
public struct Record {
    /// レコードのタイトル
    title: String,
    /// レコードのアーティスト。`Artist`タイプを使用
    artist: Artist,
    /// レコードがリリースされた年
    year: u16,
    /// レコードがデビューアルバムかどうか
    is_debut: bool,
    /// レコードのエディション
    edition: Option<u16>,
}

上記の例では、5つのフィールドを持つRecord構造体を定義しています。titleフィールドはString型、artistフィールドはArtist型、yearフィールドはu16型、is_debutフィールドはbool型、editionフィールドはOption<u16>型です。editionフィールドはエディションがオプショナルであることを表すためにOption<u16>型を使用しています。

構造体はデフォルトでプライベートであり、定義されたモジュールの外部からはインポートおよび使用することができません。フィールドもプライベートであり、モジュールの外部からアクセスすることはできません。異なる可視性修飾子についての詳細は可視性で説明しています。

構造体のフィールドはプライベートであり、構造体を定義するモジュール内でのみアクセスが可能です。他のモジュールで構造体のフィールドを読み書きするには、構造体を定義するモジュールがフィールドにアクセスするための公開関数を提供している必要があります。

インスタンスの作成と使用

構造体の定義方法について説明しました。次に、構造体を初期化して使用する方法を見てみましょう。構造体は struct_name { field1: value1, field2: value2, ... } の構文を使用して初期化できます。フィールドは任意の順序で初期化でき、すべてのフィールドを設定する必要があります。

let mut artist = Artist {
    name: b"The Beatles".to_string()
};

上記の例では、Artist構造体のインスタンスを作成し、nameフィールドに文字列 "The Beatles" を設定しています。

構造体のフィールドにアクセスするには、フィールド名の前に.演算子を使用します。

// `Artist`構造体の`name`フィールドにアクセス
let artist_name = artist.name;

// `Artist`構造体のフィールドにアクセス
assert!(artist.name == string::utf8(b"The Beatles"), 0);

// `Artist`構造体の`name`フィールドを変更
artist.name = string::utf8(b"Led Zeppelin");

// `name`フィールドが変更されたことを確認
assert!(artist.name == string::utf8(b"Led Zeppelin"), 1);

構造体を定義するモジュールのみがそのフィールドにアクセスできます(可変および不変の両方)。したがって、上記のコードはArtist構造体と同じモジュール内にある必要があります。

構造体のアンパック

構造体はデフォルトで非破棄可能であり、初期化された構造体の値は使用されなければなりません:ストアされるかアンパックされます。構造体のアンパックは、それをフィールドに分解することを意味します。これはletキーワードに続いて構造体名とフィールド名を使用して行われます。

// `Artist`構造体をアンパックし、`name`フィールドの値を持つ新しい変数`name`を作成
let Artist { name } = artist;

上記の例では、Artist構造体をアンパックし、nameフィールドの値を持つ新しい変数nameを作成しています。変数が使用されていないため、コンパイラは警告を発生させます。警告を抑制するには、変数が意図的に使用されていないことを示すためにアンダースコア_を使用できます。

// `Artist`構造体をアンパックし、`name`フィールドを無視
let Artist { name: _ } = artist;