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

オプション型

オプション型は値がない (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型の値を取り出す必要があります。これをアンラップと呼びます。

オプション型のアンラップは以下の4つの方法があります。

  1. オプション型の値 orelse デフォルト値
  2. オプション型の値.?
  3. if(オプション型の値) |変数名|
  4. if(オプション型の値) |*変数名|

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: ?*mut u64 = null;

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

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

    var value: u64 = 42;
    // ポインタは`value`を参照する
    pointer = &mut 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));
}

Chapter 1

Chapter 2

Chapter 3

Chapter 4

Chapter 5

Chapter 6

Chapter 7

Chapter 8

Chapter 9

Chapter 10

Chapter 11

Chapter 12

Chapter 13

Chapter 14

Chapter 15

Appendix

Error Explanation

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