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

オプション型

オプション型は値がない (null) かもしれないことを表現する型です。オプション型を導入することで、型から値がない場合があることを識別できます。このことにより、値がないことのチェックを忘れることがなくなり、バグを未然に防ぐことができます。

オプション型の定義

?Tのように、任意の型名の前のはてなマーク (?) をつけることで、オプション型になります。

examples/ch03-user-defined-types/src/optional.zen:4:6

test "define optional types" {
    const optional: ?u64 = 42;
}

これは、u64のオプション型です。オプション型に値がないことを表す場合、nullを代入します。

examples/ch03-user-defined-types/src/optional.zen:8:10

test "initialize with null" {
    const optional: ?u64 = null;
}

オプション型は、nullとの一致比較が可能です。

examples/ch03-user-defined-types/src/optional.zen:44:47

test "compare equal null" {
    var optional: ?u64 = null;
    ok(optional == null);

オプション型のアンラップ

オプション型?Tに格納されたT型の値を使うためには、オプション型からT型の値を取り出す必要があります。これをアンラップと呼びます。

orelse演算子を使用して、オプション型をアンラップできます。orelse演算子は、オプション型の値 orelse デフォルト値という構文で使用します。

examples/ch03-user-defined-types/src/optional.zen:12:22

test "unwrap with orelse operator" {
    var optional: ?u64 = 42;
    // `null`でなければアンラップして値を得る
    const value = optional orelse 0;
    ok(value == 42);

    optional = null;
    // `null`であればデフォルト値を得る
    const default = optional orelse 0;
    ok(default == 0); 
}

オプション型がnullでないことが明らかな場合、?演算子でアンラップすることも可能です。

examples/ch03-user-defined-types/src/optional.zen:24:27

test "unwrap with ? operator" {
    var optional: ?u64 = 42;
    ok(optional.? == 42);
}

?演算子は、オプション型インスタンス orelse unreachableのシンタックスシュガーです。オプション型インスタンスがnullの場合、安全性保護付き未定義動作により、実行時にパニックが発生します。

ifにはオプション型がnullかどうか検査した上で、アンラップする構文が用意されています。if(オプション型の値) |アンラップした値の変数名| { 本体ブロック }を使います。

examples/ch03-user-defined-types/src/optional.zen:29:34

test "unwrap with if" {
    var optional: ?u64 = 42;
    if (optional) | value | {
        ok(value == 42);
    }
}

オプション型の値の参照が必要な場合は、ポインタ型で値を取得します。

examples/ch03-user-defined-types/src/optional.zen:36:42

test "get reference of unwrapped value" {
    var optional: ?u64 = 42;
    if (optional) | *value | {
        value.* = 52;
    }
    ok(optional.? == 52);
}

ifと同様に、whileにもオプション型がnullかどうか検査した上で、アンラップする構文が用意されています。while (オプション型の値) |アンラップした値の変数名| { 本体ブロック }という構文になります。

オプション型ポインタ

C言語では、ポインタが何も参照していないことを示すため、NULLポインタを利用します。NULLポインタをデリファレンスした結果は、未定義でありシステムがどのような状態に陥るかわかりません。NULLポインタを取り扱うことはバグの原因になります。

Zenでは、NULLポインタを取り扱いません。ポインタが何も参照していないことを示すために、オプション型でポインタを包み、オプション型のnullを使用します。このようなオプション型で包まれたポインタをオプション型ポインタと呼びます。

examples/ch03-user-defined-types/src/optional.zen:52:54

test "optional pointer" {
    // ポインタは何も参照していない
    var pointer: ?*u64 = null;

オプション型ポインタにポインタを代入する方法は、通常のポインタと同じです。

examples/ch03-user-defined-types/src/optional.zen:56:58

    var value: u64 = 42;
    // ポインタは`value`を参照する
    pointer = &value;

オプション型ポインタには、直接デリファレンス演算子が使えません。

examples/ch03-user-defined-types/src/optional.zen:60:62

    // Compile error
    // オプション型は直接デリファレンスできない
    // pointer.* = 52;

オプション型ポインタは、ポインタを使う前にアンラップします。

examples/ch03-user-defined-types/src/optional.zen:64:69

    // nullでないことを検査し、アンラップする
    if (pointer) |non_null| {
        non_null.* = 52;
    }

    ok(value == 52);

オプション型ポインタでは、nullの値に0を使います。そのため、オプション型ポインタがメモリを専有する量は、通常のポインタと同じです。

examples/ch03-user-defined-types/src/optional.zen:72:74

test "size of optional pointer" {
    ok(@sizeOf(?*u64) == @sizeOf(usize));
}

☰ 人の生きた証は永遠に残るよう ☰
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.