Sometimes
it is necessary to manipulate data whose type varies or cannot be determined at
compile time. In these cases, one option is to use variables and parameters of
type Variant, which represent values that can change type at runtime.
Variants offer greater flexibility but consume more memory than regular
variables, and operations on them are slower than on statically bound types.
Moreover, illicit operations on variants often result in runtime errors, where
similar mistakes with regular variables would have been caught at compile time.
You can also create custom variant types.
By
default, Variants can hold values of any type except records, sets, static
arrays, files, classes, class references, and pointers. In other words,
variants can hold anything but structured types and pointers. They can hold
interfaces, whose methods and properties can be accessed through them. (See Object interfaces.) They can hold
dynamic arrays, and they can hold a special kind of static array called a variant
array. (See Variant arrays.) Variants
can mix with other variants and with integer, real, string, and Boolean values
in expressions and assignments; the compiler automatically performs type conversions.
Variants
that contain strings cannot be indexed. That is, if V is a variant that holds a
string value, the construction V[1] causes a runtime error.
You can
define custom Variants that extend the Variant type to hold arbitrary values.
For example, you can define a Variant string type that allows indexing or that
holds a particular class reference, record type, or static array. Custom
Variant types are defined by creating descendants to the TCustomVariantType
class.
A variant
occupies 16 bytes of memory and consists of a type code and a value, or pointer
to a value, of the type specified by the code. All variants are initialized on
creation to the special value Unassigned. The special value Null
indicates unknown or missing data.
The standard function VarType returns a variant’s type code. The varTypeMask constant is a bit mask used to extract the code from VarType’s return value, so that, for example,
VarType(V)
and varTypeMask = varDouble
returns True if V contains a Double
or an array of Double. (The mask simply hides the first bit, which
indicates whether the variant holds an array.) The TVarData record type
defined in the System unit can be used to typecast variants and gain
access to their internal representation. See the online Help on VarType
for a list of codes, and note that new type codes may be added in future
implementations of Object Pascal.
Data types and variables: Overview
TVarData type
有时必需处理那些类型变化或不确定的数据,这时可以选用Variant类型的变量和参数。Variant类型表示的值在运行时可以改变数据类型。变体类型比常规类型具有更大的灵活性,但变体类型比静态范围类型占用较多的内存并且处理速度较慢。此外,对变体类型的非法操作通常运行时错误,而类似的错误对于常规类型则在编译时就能避免。还可以创建定制的变体类型。
默认情况下,变体可以保存除记录、集合、静态数组、文件、类、类引用、指针之外的任何类型的值。也就是说,变体可以保存除结构类型和指针之外的任何类型。变体可以保存接口以及接口中可以访问的方法和属性。(见对象接口。)变体可以保存动态数组,可以保存变体数组(variant array,静态数组的一种特殊类型)。(见变体数组。)在表达式和赋值语句中,变体可以与其他变体以及整数、实数、串、布尔值等混合,编译器会自动完成类型转换。
包含串的变体不能被索引。例如,如果V是一个保存了串值的变体,那么 V[1] 将导致运行时错误。
可以定义定制的变体来扩充变体类型,以保存任意值。例如,可以定义一个允许索引的变体串类型,或者保存关键的类引用、记录类型或静态数组类型等。定制的变体类型通过创建TCustomVariantType类的后裔来定义。
一个变体占用16字节的内存,由一个类型代码和一个值或值的指针(指针类型由类型代码决定)组成。所有变体在创建时都被初始化为一个特别的值Unassigned。特殊值Null表示未知或丢失的数据。
标准函数VarType返回变体的类型代码。varTypeMask常量是一个用于提取VarType返回值的代码的比特掩码。例如,对于表达式
VarType(V)
and varTypeMask = varDouble
如果V包含了一个Double或一个Double数组,那么表达式返回True。(掩码只是隐藏了第一个比特位,该位表示变体是否保存了数组。)System单元中定义的TVarData记录类型可以用于对变体进行类型转换,以访问变体的内部表示。查看关于VarType的联机帮助,可以得到变体的类型代码列表。在未来的Object Pascal实现中,可能会增加新的类型代码。
TVarData类型
编者注
下面的代码举例说明了预定义常量Unassigned和标准函数Null的用法,以及标准函数VarIsNULL和VarIsEmpty的用法。
对于如下声明
var
V: Variant;
如下语句序列
V := Unassigned;
if V = NULL then
ShowMessage('V = NULL');
将引发运行时错误;
如下语句序列
V := NULL;
if V = Unassigned then
ShowMessage('V = Unassigned');
将引发运行时错误;
如下语句序列
V := NULL;
if V = NULL then ShowMessage('V = NULL');
将正确执行;
如下语句序列
V := Unassigned;
if VarIsNULL(V) then
ShowMessage('V is NULL')
else
ShowMessage('V is not NULL');
将正确执行,此时VarIsNULL(V)返回False。
如下语句序列
V :=
Unassigned;
if
VarIsEmpty(V) then//函数返回True
ShowMessage('V is empty')
else
ShowMessage('V is not
empty');
V := NULL;
if VarIsEmpty(V) then//函数返回False
ShowMessage('V is empty')
else
ShowMessage('V
is not empty');
将正确执行。