tonari note

オンラインゲームエンジニアの雑記

Optionクラスを公開しました

Optionクラス(GitHub)

Nullableでは以下のような演算が可能です。

演算のどちらかがnullだった場合、結果もnullになります。

参照型の場合、nullに対するメンバを呼び出そうとするとエラーになります。
これを回避するためにOptionクラスでオブジェクトをラッピングし、使用することにしました。

具体的には、値がある場合を「Some value」、値がない場合を「None」と表現しています。

var optional = new Option<string>(null); // None
var optional = new Option<string>(); // None

まず、nullを放り込むと、Optionの値はNoneになります。
また、引数なしのコンストラクタはNoneを返します。

var optional = new Option<string>("ALL for FUN, FUN for ALL.");
var optional = "ALL for FUN, FUN for ALL.".ToOption();
var optional = Option<string>.Create("ALL for FUN, FUN for ALL.");

Optionに変換する方法は3種類あります。

var a = 5.ToOption();
var b = 5.ToOption();
/** a == b : true **/

Optionは等価比較ができます。
Some同士の比較は中身の値の等価比較と同じになります。
None同士の比較はtrueになります。
Optionの型引数が違うと、比較時にコンパイルエラーとなります。

if (Optional<string>.Create(""))
{
    /** Someの場合はこちら **/
}

if (Optional<string>.None) {}
else
{
    /** Noneの場合はこちら **/
}

// エラー
// bool b = Option<string>.None;

Optionはifの条件式に使用することができます。
だからといって、単純なboolへの変換はできません。

var optionalDefault = Option<string>.Defalut; // None
var optionalDefault = Option<int>.Defalut; // Some 0

使いどころがよく解りませんが、型引数の規定値のOptionを取得することができます。

(string)("Al Maaz".ToOption());

Optionalは型引数の型に明示的にキャストすることができます。
Noneの場合は、その型の既定値を返します。

var length =
    from str in Option<string>.Create("abcde")
    select str.Length;
/** length : Some 5 **/

クエリ構文を用いてOptionがラップしている値に対して操作をすることができます。
返り値はOptionになります。

var length =
    from str in Option<string>.Create(null)
    select str.Length;
/** length : None **/

Noneに対する操作は必ずNoneを返します。

var str =
    from substr1 in Option<string>.Create("abcde")
    from substr2 in Option<string>.Create("fghij")
    select substr1 + substr2;
/** str : Some "abcdefghij" **/

from句を繋げて、selectで複数のOptionを操作することができます。