構造体

Dではstructで複合型もしくはカスタム型を定義できます:

struct Person {
    int age;
    int height;
    float ageXHeight;
}

structは(newで作成されない限り)常にスタックに構築され、 代入や関数呼び出しの引数では値としてコピーされます。

auto p = Person(30, 180, 3.1415);
auto t = p; // コピー

struct型のオブジェクトが新規に作成されるとき、 そのメンバはstruct内で定義された順に初期化されます。 カスタムコンストラクタはthis(...)メンバ関数で定義できます。 名前の衝突を回避したいときは、thisを使って現在のインスタンスに明示的にアクセスできます:

struct Person {
    this(int age, int height) {
        this.age = age;
        this.height = height;
        this.ageXHeight = cast(float)age * height;
    }
        ...

Person p = Person(30, 180); // 初期化
p = Person(30, 180);  // 新しいインスタンスへ代入

structは複数のメンバ関数を持つことができます。 メンバ関数はデフォルトでpublicで、外部からアクセスが可能です。 これはprivateにすることも可能で、その場合同じstructのメンバ関数か、 同じモジュール内のコードからのみ呼び出せるようになります。

struct Person {
    void doStuff() {
        ...
    private void privateStuff() {
        ...

p.doStuff(); // メソッド doStuff を呼び出す
p.privateStuff(); // これは禁止されています

Constメンバ関数

メンバ関数がconstで宣言されている場合、そのメンバを変更することはできません。 これはコンパイラにより強制されます。 メンバ関数をconstにすると、constまたはimmutableオブジェクトから呼び出せるようになり、 さらにこの関数がオブジェクトの状態を変更しないことが呼び出し元に保証されます。

Staticメンバ関数

メンバ関数がstaticで宣言されると、 その関数はインスタンス化されたオブジェクトなしに呼び出せるようになります (例: Person.myStatic())が、非staticメンバにアクセスできなくなります。 これはメソッドがオブジェクトメンバフィールドにアクセスする必要はないが、 論理的には同じクラスに属するときに使えます。 明示的インスタンスを作ることなく機能を提供するのにも使えます。 例えばシングルトンデザインパターンの実装にはstaticが使われることがあります。

継承

structは他のstructから継承できないことに注意してください。 型ヒエラルキーは、後のセクションで見ていくクラスを用いてのみ構築可能です。 しかし、alias thismixinで簡単にポリモーフィックな継承が可能です。

掘り下げる

エクササイズ

struct Vector3に以下の関数を実装し、サンプルアプリケーションを正常に実行されるようにしましょう:

  • length() - ベクトルの長さを返す
  • dot(Vector3) - 2つのベクトルのドット積を返す
  • toString() - ベクトルの文字列表現を返す 関数 std.string.formatformat("MyInt = %d", myInt)のようなprintf風の構文を使って文字列を返します。 文字列は後のセクションで詳しく解説します。

rdmd playground.d