std.variant
このモジュールは discriminated union 型( タグ付きunion, 代数的データ型 としても知られている)を実装しています。このような型は、 任意の型を受け取るバイナリインターフェイスや、スクリプト言語とのインターフェイス、 プロトタイピング中などに有用です。Synopsis:
Variant a; // 使用前には代入すること。そうでないと例外 // 整数で初期化; int型になる Variant b = 42; assert(b.type == typeid(int)); // 値を読む assert(b.peek!(int) !is null && *b.peek!(int) == 42); // 言語の規則に基づく自動変換 auto x = b.get!(real); // variantを含む他の型をなんでも代入できる a = b; a = 3.14; assert(a.type == typeid(double)); // 暗黙変換は組み込み型と同様に動作 assert(a > b); // 変換可能性のチェック assert(!a.convertsTo!(int)); // double は int に変換できない // 文字列とその他配列型のサポート a = "now I'm a string"; assert(a == "now I'm a string"); a = new int[42]; // 配列も代入可能 assert(a.length == 42); a[5] = 7; assert(a[5] == 7); // クラスの値も代入可能 class Foo {} auto foo = new Foo; a = foo; assert(*a.peek!(Foo) == foo); // 完全な型情報を保持Source:
std/variant.d License:
Boost License 1.0. Authors:
Andrei Alexandrescu Credits:
Brad Roberts によりレビューされました。また Daniel Keep によるコードレビューで以下の改善が進みました: (1)配列サポートの改善 (2)連想配列のサポート (3)GCに優しい実装。
- VariantN は実装詳細の一部で、ユーザーコードで使われるのは非常にまれです。
VariantN
を裏で使用する型は2つあります:
- Algebraic: 限定された型のみを格納する discriminated union (例えば Algebraic!(int, double, string) はこの3つの型のみを格納でき、その他の値は全て拒否します。 )
- Variant: 特に型を限定しない discriminated union です。 制限としては、格納できる最大の型は、 最大の組み込み型のサイズ以下でなければいけません。 これはつまり、Variant には全てのプリミティブ型と 大きな struct 以外の任意のユーザー定義型を入れられるということになります
Algebraic と Variant のどちらも VariantN のインターフェイスを提供しています。(個別のドキュメントは下参照)
VariantN は、格納できる最大の型のサイズ (maxDataSize)と、格納可能な型のリスト (AllowedTypesX)をパラメタにとる discriminated union 型です。 リストが空だった場合、maxDataSize(を境界整列のため切り上げた値)以下のサイズの型ならなんでも VariantN オブジェクトに格納できるようになります。
- コンパイル時に、T と AllowedTypesX を比べて
T を VariantN 格納できるかどうか判定します。
AllowedTypesX が空ならば、maxSize 以下のサイズを持つ全ての型が格納可能です。
- 引数から VariantN のオブジェクトを構築します。
格納不可能な型の場合、コンパイル時にエラーになります。
- VariantN に値を代入します。
格納不可能な型の場合、コンパイル時にエラーになります。
- VariantN に値を代入します。
格納不可能な型の場合、コンパイル時にエラーになります。
- VariantN に有効な値が
(初期化もしくは代入で)
格納されてるときに true になります。
Example:
Variant a; assert(!a.hasValue); Variant b; a = b; assert(!a.hasValue); // まだなにも格納されていない a = 5; assert(a.hasValue);
- VariantN に
ぴったり T 型の値が格納されていたら、その値へのポインタを返します。
そうでなければ null を返します。
T がそもそも格納不可能な型の場合、peek がコンパイルエラーになります。
Example:
Variant a = 5; auto b = a.peek!(int); assert(b !is null); *b = 6; assert(a == 6);
- 現在格納されている値の typeid を返します。
- VariantN
に格納されているオブジェクトが型 U に暗黙変換可能なときに true を返します。変換可能性のチェックは
ImplicitConversionTargets で行われます。
- VariantN
に格納されているオブジェクトが型 U に暗黙変換可能なときに true を返します。変換可能性のチェックは
ImplicitConversionTargets で行われます。
- VariantN オブジェクトに格納された値を、
指定された型 T
(正確には DecayStaticToDynamicArray!(T)) に暗黙変換して返します。
暗黙変換が不可能な場合、VariantException 例外を投げます。
- VariantN オブジェクトに格納された値を、
指定された型 T
(正確には DecayStaticToDynamicArray!(T)) に暗黙変換して返します。
暗黙変換が不可能な場合、VariantException 例外を投げます。
- VariantN に格納された値を指定の型 T に明示的に変換 (coerce) して返します。
T が文字列の場合は、値は文字列に整形されます。
VariantN に文字列が格納されている場合は、
文字列を T 型の値としてparseして返します
変換が失敗した場合、VariantException 例外を投げます。
- 格納された値を文字列化して返します。
- "==" と "!=" 演算子で使われる等値性判定です。
- "==" と "!=" 演算子で使われる等値性判定です。
- "<", "<=", ">", ">=" 演算子で使われる比較処理です。
格納された値と rhs の間で意味のある比較ができない場合、
例外を投げます。
- "<", "<=", ">", ">=" 演算子で使われる比較処理です。
格納された値と rhs の間で意味のある比較ができない場合、
例外を投げます。
- 格納された値のハッシュ値を計算します。
- VariantN オブジェクトと数値型の間の算術演算です。
計算結果は、
演算対象の二つの型から決まる型を格納した
VariantN オブジェクトで返されます。
型変換はDの組み込みの算術演算と同じ規則で決まります。
- VariantN オブジェクトと数値型の間の算術演算です。
計算結果は、
演算対象の二つの型から決まる型を格納した
VariantN オブジェクトで返されます。
型変換はDの組み込みの算術演算と同じ規則で決まります。
- template opMul(T)
template opDiv(T)
template opMod(T)
template opAnd(T)
template opOr(T)
template opXor(T)
template opShl(T)
template opShr(T)
template opUShr(T)
template opCat(T)
template opAddAssign(T)
template opSubAssign(T)
template opMulAssign(T)
template opDivAssign(T)
template opModAssign(T)
template opAndAssign(T)
template opOrAssign(T)
template opXorAssign(T)
template opShlAssign(T)
template opShrAssign(T)
template opUShrAssign(T)
template opCatAssign(T) - ditto
ditto
- ditto
ditto
- 配列および連想配列演算です。VariantN が(連想)配列を格納している場合、
添え字に対応する値が取り出せます。それ以外の場合は例外を投げます。
Example:
auto a = Variant(new int[10]); a[5] = 42; assert(a[5] == 42); int[int] hash = [ 42:24 ]; a = hash; assert(a[42] == 24);
Caveat:
現在のD言語の制限により、読み込んで変更して書き換える演算、つまり op= は正しく動作しません:
Variant a = new int[10]; a[5] = 42; a[5] += 8; assert(a[5] == 50); // fails, a[5] is still 42
- 配列および連想配列演算です。VariantN が(連想)配列を格納している場合、
添え字に対応する値が取り出せます。それ以外の場合は例外を投げます。
Example:
auto a = Variant(new int[10]); a[5] = 42; assert(a[5] == 42); int[int] hash = [ 42:24 ]; a = hash; assert(a[42] == 24);
Caveat:
現在のD言語の制限により、読み込んで変更して書き換える演算、つまり op= は正しく動作しません:
Variant a = new int[10]; a[5] = 42; a[5] += 8; assert(a[5] == 50); // fails, a[5] is still 42
- VariantN が(連想)配列を格納している場合、
その配列の長さが取り出せます。
それ以外の場合は例外を投げます。
- VariantN が配列を格納している場合、dg を配列の各要素に適用します。 そうでない場合、例外を投げます。
将来的には、 格納されている可能性のある型すべてについてユーザーコードで処理されているかをコンパイル時チェックして、 エラーを大幅に減らすような機能の追加を考えています。
BUGS:
現在のところ、Algebraic で再帰的なデータ型を定義することはできません。 この制限は将来的には取り除かれる予定です。
Example:
auto v = Algebraic!(int, double, string)(5); assert(v.peek!(int)); v = 3.14; assert(v.peek!(double)); // auto x = v.peek!(long); // コンパイルエラー。long は入らない // v = '1'; // コンパイルエラー。char は入らない
Example:
auto a = variantArray(1, 3.14, "Hi!"); assert(a[1] == 3.14); auto b = Variant(a); // variantの配列をvariantに格納 assert(b[1] == 3.14);std.boxer モジュールの boxArray 関数と似た機能が欲しい場合は、以下のように実装します:
// old Box[] fun(...) { ... return boxArray(_arguments, _argptr); } // new Variant[] fun(T...)(T args) { ... return variantArray(args); }これは意図的にこうなっています。 Variant の構築時には、 高速な処理のために格納する型の静的な型情報が必要となります。
- 未初期化のVariantが 代入, hasValue 以外で使われた場合
- get や coerce が非互換の型で呼び出された場合
- 比較できない値を格納した Variant を比較しようとした場合
- 変換や比較の変換元
- 変換や比較の変換先