オフィスアワーがそろそろ始まるよ!()

列挙型 (enum)

列挙型 (enum) は、一連の整数にタグを与えるための仕組みです。

列挙型の定義

列挙型の定義は、const 型名 = enum { タグ名, ... };で行います。

examples/ch03-user-defined-types/src/enum.zen:4:8

const State = enum {
    Wait,
    Ready,
    Running,
};

列挙型の値は、通常の変数定義と同じように定義できます。

examples/ch03-user-defined-types/src/enum.zen:10:15

test "define an enum variant" {
    const s = State.Running;
    ok(s == State.Running);
    ok(s != State.Wait);
}

同じ列挙型同士は一致比較できます。異なる列挙型同士や、列挙型と整数の比較はできません。

列挙型リテラル

型推論可能な場所で列挙型リテラルを使用する場合、列挙型名を省略した.タグ名の省略記法が利用可能です。

    // 以下の2行は同等
    ok(s == State.Running);
    ok(s == .Running);

タグと整数値の相互変換

デフォルトでは、列挙型のタグには、0から順番に整数値が割り当てられます。タグを整数型に変換するには、組込み関数の@enumToIntを使用します。

examples/ch03-user-defined-types/src/enum.zen:17:21

test "enum to int" {
    ok(@enumToInt(State.Wait) == 0);
    ok(@enumToInt(State.Ready) == 1);
    ok(@enumToInt(State.Running) == 2);
}

逆に、整数値から列挙型のタグに変換するには、組込み関数の@intToEnumを使用します。

examples/ch03-user-defined-types/src/enum.zen:23:25

test "int to enum" {
    ok(@intToEnum(State, 2) == State.Running);
}

タグに割り振る整数値の設定

タグに割り振る整数値を設定することもできます。

examples/ch03-user-defined-types/src/enum.zen:27:35

const Number = enum {
    One = 1,
    Two = 2,
    Three = 3,
};

test "override enum number" {
    ok(@enumToInt(Number.One) == 1);
}

デフォルトでは、Zenは列挙型に対して、タグの個数を表現可能な最小限ビット幅の符号なし整数型を割り当てます。この整数型を列挙型のタグ型と呼びます。上の列挙型Numberのタグ型はu2になります。

examples/ch03-user-defined-types/src/enum.zen:37:39

test "bit-width of enum type" {
    ok(@TagType(Number) == u2);
}

そのため、表現に3ビット必要な整数4を割り当てると、コンパイルエラーになります。

const Number = enum {
    One = 1,
    Two = 2,
    Three = 3,
    Four = 4,
};
error[E02047]: unable to convert '4' to 'u2'
    Four = 4,
           ~

タグ型の定義

列挙型のタグ型を設定することもできます。enum(タグ型)でタグ型を設定します。

examples/ch03-user-defined-types/src/enum.zen:41:50

const BigNumbers = enum(u32) {
    KILO = 1_000,
    MEGA = 1_000_000,
    GIGA = 1_000_000_000,
};

test "specify tag type" {
    ok(@TagType(BigNumbers) == u32);
    ok(@enumToInt(BigNumbers.GIGA) == 1_000_000_000);
}

switch

列挙型はswitchでそれぞれのタグを場合分けすることができます。

次の曜日を表す列挙型を例に説明します。

examples/ch03-user-defined-types/src/enum.zen:52:60

const DayOfWeek = enum {
    Sunday,
    Monday,
    Tuesday,
    Wednesday,
    Thursday,
    Friday,
    Saturday,
};

列挙型をswitchで取り扱う構文は、以下の通りです。

switch (列挙型の値) {
    タグ1 => タグ1に対する処理,
    タグ2 => タグ2に対する処理,
    ...,
    else => その他の場合に対する処理,
}

ノート: else => その他の場合に対する処理,の分岐は、列挙型のタグに対する分岐が網羅されていれば、省略可能です。

Zenのswitchは式であるため、値を返すことができます。その曜日が平日かどうかをブール型で返す処理は、次のように書くことができます (ただしこの書き方は冗長です) 。

examples/ch03-user-defined-types/src/enum.zen:62:72

fn isWeekday(day: DayOfWeek) bool {
    return switch (day) {
        .Monday => true,
        .Tuesday => true,
        .Wednesday => true,
        .Thursday => true,
        .Friday => true,
        .Saturday => false,
        .Sunday => false,
    };
}

列挙型に対するswitchは、必ず全てのヴァリアントに対する場合分けを書かねばなりません。上のswitch式から、Sundayの場合を消した場合、次のコンパイルエラーになります。

error: enumeration value 'src.enum_define.DayOfWeek.Sunday' not handled in switch
    return switch (day) {
           ^

switch式の詳細な利用方法については、4.5 パターンマッチで説明します。

メソッドの定義

列挙型には関数およびメソッドを定義することができます。

関数は列挙型名前空間内の関数として扱われ、列挙型.関数名で呼び出すことができます。

examples/ch03-user-defined-types/src/enum.zen:78:101

const Os = enum {
    Linux,
    Windows,
    MacOSX,
    FreeBSD,

    fn allOs() []const u8 {
        return "Linux, Windows, MacOSX, FreeBSD"[0..];
    }
};

const equalSlices = std.testing.equalSlices;
test "namespaced function in enum" {
    equalSlices(u8
              , "Linux, Windows, MacOSX, FreeBSD"
              , Os.allOs());
}

メソッドは第一引数に列挙型の値 (またはそのポインタ) を受け取る関数です。メソッドは、変数名.メソッド名で呼び出すことができます。

examples/ch03-user-defined-types/src/enum.zen:103:105

test "method" {
    const linux = Os.Linux;
    ok(linux.isXnix() == true);
};

メソッドは次のように呼び出すこともできます。

examples/ch03-user-defined-types/src/enum.zen:104:107

    const linux = Os.Linux;
    // 次の3行は同等です。
    ok(linux.isXnix() == true);
    ok(Os.Linux.isXnix() == true);
    ok(Os.isXnix(Os.Linux) == true);

関連する組込み関数

列挙型に関連する組込み関数を、次の列挙型を例に紹介します。

examples/ch03-user-defined-types/src/enum.zen:110:115

const Value = enum {
    Zero,
    One,
    Two,
    Three,
};

@enumToInt

列挙型の値を整数値に変換します。

examples/ch03-user-defined-types/src/enum.zen:117:119

test "@enumToInt" {
    ok(@enumToInt(Value.Zero) == 0);
}

@intToEnum

整数値を列挙型の値に変換します。

examples/ch03-user-defined-types/src/enum.zen:121:123

test "@intToEnum" {
    ok(@intToEnum(Value, 0) == .Zero);
}

@TagType

列挙型のタグ型 (列挙型に割り当てられた整数型) を取得します。

examples/ch03-user-defined-types/src/enum.zen:125:127

test "@TagType" {
    ok(@TagType(Value) == u2);
}

@memberCount

列挙型にいくつのタグがあるか、を取得します。

test "@memberCount" {
    ok(@memberCount(Value) == 4);
} 

@memberName

列挙型のタグ名を、タグに割り当てられている整数値から取得します。

examples/ch03-user-defined-types/src/enum.zen:133:135

test "@memberName" {
    equalSlices(u8, "Zero", @memberName(Value, 0));
}

@tagName

列挙型のタグ名を、列挙型の値から取得します。

examples/ch03-user-defined-types/src/enum.zen:137:139

test "@tagName" {
    equalSlices(u8, "Zero", @tagName(Value.Zero));
}

☰ 人の生きた証は永遠に残るよう ☰
Copyright © 2018-2019 connectFree Corporation. All rights reserved.
Zen, the Zen three-circles logo and The Zen Programming Language are trademarks of connectFree corporation in Japan and other countries.