バリアント型(Delphi)
データ型、変数、定数:インデックス への移動
このトピックでは、バリアント データ型の使用方法について説明します。
バリアント型の概要
型が変化するデータやコンパイル時に型を決定できないデータの操作が必要な場合があります。 このような場合の 1 つの選択肢は、実行時に型を変更できる値を表す、バリアント型の変数やパラメータを使用することです。 バリアントを使用すると、柔軟性が向上しますが通常の変数よりもメモリを多く使用します。バリアントの操作は、静的にバインドした型よりも遅くなります。 さらに、通常の変数であればコンパイル時に発見できるような間違いでも、バリアントに対する不正な操作は多くの場合実行時エラーを発生させます。 カスタムのバリアント型を作成することもできます。
デフォルトではバリアントは、レコード、集合、静的配列、ファイル、クラス、クラス参照、およびポインタを除くすべての型の値を保持できます。 言い換えると、バリアントは、構造化型とポインタ以外のすべてを保持できます。 バリアントはインターフェイスを保持できます。インターフェイスのメソッドとプロパティには、バリアントからアクセスできます (「オブジェクト インターフェイス(Delphi)」を参照。)バリアントは、動的配列、およびバリアント配列と呼ばれる特殊な静的配列を保持できます。 (このトピックの後半にある「バリアント配列」を参照)。 バリアントは、式や代入文で、他のバリアントや、整数値、実数値、文字列値、および Boolean 値と混在させて使うことができます。コンパイラは、自動的に型変換を行います。
文字列を含むバリアントは、インデックス付けできません。 たとえば、V がバリアントで文字列値を持つ場合、構文 V[1] は実行時エラーを発生させます。
任意の値を保持できるようにバリアント型を拡張した、カスタム バリアントを定義できます。 たとえば、インデックス付けできるバリアント文字列型、あるいは特定のクラス参照、レコード型、または静的配列を保持するバリアント文字列型を定義できます。 カスタム バリアント型は、TCustomVariantType クラスの下位クラスを作成することによって定義します。
メモ: これは、そしてほとんどすべてのバリアントの機能は、System.Variants ユニットに実装されています。
メモ: バリアント レコードは、本質的に "安全でない" と考えられます。 バリアント レコードは "absolute" 指令の使用に非常によく似ていますが、これは、レコードのバリアント フィールド部分が文字どおりメモリ内で互いにオーバーレイしているからです。 ある値を 1 つの型として代入してから、それを別の型として読み取ることができます。 バリアントを使用する場合、安全でないコードについてのコンパイラ警告は「W1047 安全でないコード '%s' (Delphi)」などで確認できます。
32 ビット プラットフォームでは、バリアントは 16 バイト レコードとして格納されます。 64 ビット プラットフォームでは、バリアントは 24 バイト レコードとして格納されます。 バリアント レコードは、型コードによって指定された型の、型コードと値または値へのポインタで構成されます。 すべてのバリアントは、作成時に特別な値 "Unassigned" で初期化されます。 特別な値 Null は、不明なデータまたは欠落したデータを示します。
標準関数 VarType は、バリアントの型コードを返します。 varTypeMask 定数は、VarType の戻り値から型コードを抽出するために使用するビット マスクです。次に例を示します。
VarType(V) and varTypeMask = varDouble
V が Double または Double の配列を保有している場合、True を返します。マスクは、単純にバリアントが配列であるかどうかを示す最初のビットを隠します。 System ユニットに定義されている TVarData レコード型を使用して、バリアントを型キャストしたり、バリアントの内部表現にアクセスしたりできます。
バリアント型の変換
整数、実数、文字列、文字、論理型は、すべてバリアント型と代入互換です。 式をバリアントとして明示的にキャストし、VarAsType と VarCast 標準ルーチンを使用して、バリアントの内部表現を変更できます。 以下のコードは、バリアントの使用方法、およびバリアントと他の型が混在している場合に行われる自動的な変換を示しています。
var V1, V2, V3, V4, V5: Variant; I: Integer; D: Double; S: string; begin V1 := 1; { integer value } V2 := 1234.5678; { real value } V3 := 'Hello world!'; { string value } V4 := '1000'; { string value } V5 := V1 + V2 + V4; { real value 2235.5678} I := V1; { I = 1 (integer value) } D := V2; { D = 1234.5678 (real value) } S := V3; { S = 'Hello world!' (string value) } I := V4; { I = 1000 (integer value) } S := V5; { S = '2235.5678' (string value) } end;
コンパイラは、以下の規則に従って型変換を行います。
バリアント型の変換規則
ターゲット: |
整数 |
実数 |
文字列 |
Boolean |
整数 |
整数形式に変換 |
実数に変換 |
文字列表現に変換 |
0 の場合、False を、その他の場合は、True を返す |
実数 |
最も近い整数に丸める |
実数形式に変換 |
地域設定を使用して文字列表現に変換 |
0 の場合、False を、その他の場合は、True を返す |
文字列 |
必要な場合は切り捨てして、整数に変換する。文字列が数値でない場合は、例外が発生する。 |
地域設定を使用して実数に変換する。文字列が数値でない場合は、例外が発生する。 |
文字列/文字形式に変換 |
文字列が、"false"(大文字と小文字を区別しない)の場合または 0 と評価される数値文字列の場合、False を、文字列が "true" または 0 でない数値文字列の場合、True を返し、その他の場合は、例外が発生する |
文字 |
string(上)と同じ |
string(上)と同じ |
string(上)と同じ |
string(上)と同じ |
Boolean |
False = 0、True:すべてのビットを 1 に設定(整数の場合 -1、バイトの場合 255) |
False = 0、True = 1 |
False = 'False'、True = 'True'(デフォルト)。グローバル変数 System.Variants.BooleanToStringRule によって変わる。 |
False = False、True = True |
Unassigned |
0 を返す。 |
0 を返す。 |
空の文字列を返す |
False を返す |
Null |
グローバル変数 System.Variants.NullStrictConvert によって決まる(デフォルトでは、例外が発生する) |
グローバル変数 System.Variants.NullStrictConvert によって決まる(デフォルトでは、例外が発生する) |
グローバル変数 System.Variants.NullStrictConvert および System.Variants.NullAsStringValue によって決まる(デフォルトでは、例外が発生)。 |
グローバル変数 System.Variants.NullStrictConvert によって決まる(デフォルトでは、例外が発生する) |
範囲外の代入は、多くの場合ターゲット変数に有効範囲の最大値を割り当てることになります。 無効なバリアント操作、代入、またはキャストを行うと、Variants.EVariantError 例外または Variants.EVariantError から派生した例外クラスが発生します。
System ユニットで宣言されている System.TDateTime 型には、特別な変換規則が適用されます。 System.TDateTime を他の型に変換する場合、通常の Double として扱われます。 整数、実数、または論理型を System.TDateTime に変換する場合、始めに Double に変換してから、日付時刻値として読み取ります。 文字列を System.TDateTime に変換する場合、地域設定を使用して日付時刻値として解釈されます。 Unassigned 値を System.TDateTime に変換する場合、実数または整数の値 0 のように扱われます。 Null 値を System.TDateTime に変換すると、例外が発生します。
Win32 プラットフォームで、バリアントが COM インターフェイスを参照している場合、変換を実行するとオブジェクトのデフォルト プロパティが読み取られ、参照している値を要求した型に変換します。 オブジェクトにデフォルト プロパティがない場合、例外が発生します。
式の中のバリアント
^、is、in を除くすべての演算子が、バリアント オペランドを使用できます。常にBooleanの結果を返す比較を除いて、バリアント値の操作はバリアントの結果を返します。 式の中でバリアントと静的な型の値を組み合わせている場合、静的な型の値は自動的にバリアントに変換されます。
これは比較には当てはまりません。比較での NULL バリアントの操作は NULL バリアントを生成します。 例:
V := Null + 3;
これは、Null バリアントを V に代入します。 デフォルトでは、比較は Null バリアントを他のすべての値より小さい一意の値として扱います。 例:
if Null > -3 then ... else ...;
この例では、if 文の else の部分が実行されます。 この動作は、NullEqualityRule と NullMagnitudeRule グローバル変数を設定することによって変更できます。
バリアント配列
通常の静的配列をバリアントに割り当てることはできません。 代わりに、標準関数 VarArrayCreate または VarArrayOf を呼び出して、バリアント配列を作成します。 例:
V: Variant; ... V := VarArrayCreate([0,9], varInteger);
これは、整数(長さ 10)のバリアント配列を作成し、バリアント V に割り当てます。 この配列は、V[0]、V[1] のようにインデックス付けすることができます。ただし、バリアント配列の要素を var パラメータとして渡すことはできません。 バリアント配列は、常に整数でインデックス付けされます。
VarArrayCreate を呼び出すときの 2 番目のパラメータは、配列の基底型の型コードです。 これらの型コードのリストについては、「VarType」を参照してください。 型コード varString を VarArrayCreate に渡さないでください。文字列のバリアント配列を作成するには、varOleStr を使用します。
バリアントは、異なるサイズ、次元、および基底型のバリアント配列を保持できます。 バリアント配列の要素には、ShortString と AnsiString を除く、バリアントに格納できる型を割り当てられます。配列の基底型が Variant の場合、各要素が異なる型を持つ場合もあります。 バリアント配列をサイズ変更するには、VarArrayRedim 関数を使用します。 バリアント配列を操作する標準ルーチンは、他には VarArrayDimCount、VarArrayLowBound、VarArrayHighBound、VarArrayRef、VarArrayLock、および VarArrayUnlock があります。
メモ: カスタム バリアントのバリアント配列は、サポートされていません。カスタム バリアントのインスタンスは、VarVariant バリアント配列に追加できるからです。
バリアント配列を含むバリアントが、他のバリアントに代入されるか、値パラメータとして渡される場合、配列全体がコピーされます。 メモリの使用効率が悪くなりますので、必要がない場合は、このような操作を実行しないでください。
OleVariant
Variant と OleVariant の主な違いは、Variant には現在のアプリケーションだけが扱い方を知っているデータ型を格納できることです。 OleVariant は、OLE オートメーションと互換性を持つように定義されたデータ型のみを保持できます。つまり、プログラム間またはネットワーク間で、送信先がデータの操作方法を知っているかどうかを気にせずに渡せるデータ型です。
カスタム データ(Delphi 文字列、または新規カスタム バリアント型など)を含む Variant を OleVariant に割り当てる場合、ランタイム ライブラリは、Variant を OleVariant 標準データ型に変換しようと試みます(たとえば、Delphi 文字列を OLE BSTR 文字列に変換する)。 たとえば、AnsiString を含むバリアントを OleVariant に割り当てると、AnsiString は WideString に変換されます。 Variant を OleVariant 型の関数パラメータに渡す場合も同じことが当てはまります。