. Variant:能动态改变类型
Var
V:Variant;
Begin
V :=
‘aaaa’;
V := 1;
V :=
1.2;
V :=
True;
End;
2. Variant 结构
TVarData
结构占用16个字节的内存,TVarData结构的头两个字节用于指示variant代表的数据类型。
紧接着6个字节是保留的,剩下的8个字节包含实际的数值或一个指向由Variant表示的数据的指针。
(a)V:Variant
TvarData(v).VType := varInteger;
TvarData(v).VInteger := 2;
ShowMessage(IntToStr(v));
(b)
V := Unassigned; // 将variant初始化为”空”
V := ‘ddddddd’;
不要直接访问TVarData的数据域,如果要访问,必须清楚作什么。
3.Variant强制类型转换
(a)Variant(x);
:将表达式x强制类型转换为Variant类型
X的结果类型必须是整数,实数,货币型,字符串,字符或布尔型
(b)也可以把Variant类型的表达式强制类型转化为简单类型
V := 1.6;
S := String(v); // s := ‘1.6’;
I := Integer(v); //I := 2;
B := Boolean(v); // 如果v的值为0.则b为false,否则为true
D := Double(v); // D现在是浮点数1.6
也可以不用使用强制类型转换,直接s := v,或者 I :=v …
(c) 表达式中的Variant
V1,v2,v3 : variant;
V1 := ‘100’;
V2 := ‘50’;
V3 := 200;
V1 := v1 + v2 + v3; // v1 := 10250
(d) v1 := v1 *v2 /v3;
这个等式运行结果出来之前,会有一个运行期的函数对这个表达式中的各个操作数进行兼容性检查,然后进行必要的转换。这将导致额外的开销,最好的办法是不用variant,如果必须要用,则进行类型的转换。这样在编译期间就能完成数据类型的转换。
V1 := Integer(v1)* Double(v2) /Integer(v3);
(e) 空和null
没有值和值为null在涉及到数据库表中的字段值运算时尤其重要。
VarEmpty表示这个variant还没有赋值
varNull 确实代表了一个数值null
4.Variant相关函数
(1)VarArrayCreate() 函数
建立variant数组
V: Variant;
V := VarArrayCreate([1, 4], varInteger); // 创建4个元素的数组
V[1] := 1; ….v[4] := 4;
可以把varVariant作为建立Variant数组的类型代码传递给函数,这样在数组中的每一个数据都可以有不同的类型,同时能通过传递附加边界创建的多维数组。
V := varArrayCreate([1,4, 1,5], varInteger);
(2) VarArrayof(); 创建一个一维数组
Function varArrayof(const values : array of variant ) :
variant;
Exp:
V := varArrayof([1, [‘delphi’],
2.2);
Variant类型内部结构
Delphi中定义了一个 variant 记录类型,TVarData,它与Variant
类型有相同的内存布局。你可以通过TVarData访问variant变量的实际类型。TVarData
结构中包含了Variant类型信息(由Vtype域表示)、一些保留域及当前值。
VType域的取值包括OLE 自动化中的所有数据类型,这些类型通常叫OLE 类型或variant
类型。以下是variant 类型的完整列表,按字母顺序排列:
varArray
varBoolean
varByRef
varCurrency
varDate
varDispatch
varDouble
varEmpty
varError
varInteger
varNull
varOleStr
varSingle
varSmallint
varString
varTypeMask
varUnknown
varVariant
Delphi中的变体Variant数组相关函数
1.VarArrayCreate
procedure TForm1.Button1Click(Sender: TObject);
var V, W : Variant;
i : Integer;
begin
V :=
VarArrayCreate([1,4], varVariant);
V[1] := 1;
V[2] := '2';
V[3] := True;
V[4] := 4.5;
for i := VarArrayLowBound(V, 1) to
VarArrayHighBound(V, 1) do
begin
Memo1.Lines.Add(V[i])
end;
W := VarArrayCreate([1,2, 1,3], varInteger);
//二维 end;
注:数组上下线取值函数不能使用Low/High,而是
VarArrayLowBound/VarArrayHighBound,其第二个参数为数组维数。 2.VarArrayOf
更快捷的创建变体数组的函数,例如:V := VarArrayOf([1, '2', True,
4.5]);
3.VarArrayRedim 调整变体数组上下限
4.VarArrayDimCount 范围变体数组维数
5.VarArrayLowBound/VarArrayHighBound
返回变体数组上/下限
6.VarArrayLock/VarArrayUnlock
避免运行时刻检查。一般用于初始化一个大数组。
例如:假设已经存在大数组A,现试图复制该数组时使用如下代码:
V := VarArrayCreate([1, 10000], varByte);
for i := 1 to 10000 do
V[i] = A[i];
一、变体类型常用的函数介绍:
Variant: 一种可以拥有各种数据类型; 也可以告诉目前存储的数据是什么类型(通过使用VarType函数);
可以给相同的Variant分配不同的数据类型,只要Variant包含数字值就可以执行算法;
variant数组只不过是variant型的数组,不必包含同类型的数据;
1、
VarArrayOf函数:更快捷的创建一维变体数组,可以创建全异的数值数组;
function
VarArrayOf(const Values: array of Variant): Variant;
VarArrayOf是一种快速(写代码快而不是运行快)的方法生成一个一维Variant数据的方法,它接受一个Variant类型的Open
Array,用这个数据生成一个一维的Variant Array of
Variant(类型为Variant)。由于Delphi对Open Array类型参数的支持,使你可以用一行语句生成一个数组。不过它有两个缺陷:只能生成一维数组;只能生成元素类型是Variant的数组。使用Variant数组,
与使用标准Delphi数组类似;
例如: MyArray := VarArrayOf(['李维', 30, '60', 60.369, 'China']);
2、
VarArrayCreate函数:
function VarArrayCreate(const Bounds:
array of Integer; VarType: TVarType): Variant;
Bounds: 告诉数组的上下界; VarType:
决定了数组的中存储什么类型的数据。其它的数组(如二维、或者其他类型等)只能用VarArrayCreate去创建,并用循环给元素赋值。
例如:创建数组的数组, 可以模仿任何类型的数据结构类型:
VarArrayX := VarArrayCreate([1,10],
varVariant);
数组的单个元素可以装载一个数组: VarArrayX[1] := VarArrayCreate([1,5],
varVariant);
3、VarArrayHighBound、VarArrayLowBound函数:返回变体数组上/下限,从1开始(1:列;2:行;3:3维的最后一维)。
function VarArrayHighBound(const A: Variant; Dim: Integer):
Integer;
4、VarArrayRedim函数:修改variant数组的最高限。
procedure
VarArrayRedim(A: Variant; HighBound: Integer);
5、VarArrayDimCount函数:返回variant数组维数
unction
VarArrayDimCount(const A: Variant): Integer;
6、VarArrayLock、VarArrayUnLock函数:避免运行时刻检查。一般用于初始化一个大数组。
function VarArrayLock(const A: Variant): Pointer;
procedure VarArrayUnlock(var A: Variant);
在对Variant数组的每一个元素进行赋值时,都要通过运行时逻辑来检查并判断数据类型的兼容性、每个元素的位置等等。为了避免运行时检查,要用VarArrayLock()函数和VarArrayUnlock()过程。VarArrayLock()函数在内存中锁定数组,使数组不再移动和改变大小,并能返回一个指向数组数据的指针。而VarArrayUnlock()过程用来对VarArrayLock()函数锁定的数组进行解锁,使数组能重新移动或改变大小。在锁定数组后,能用更有效的方法对数组进行初始化。
7、VarArrayRef函数:获得variant指向的数据
function
VarArrayRef(const A: Variant): Variant;
8、VarIsArray函数:是一个简单的布尔检查函数,判断是否是一个
Variant数组,是则返回True
function VarIsArray(const A:
Variant): Boolean; overload;
function VarIsArray(const A: Variant; AResolveByRef: Boolean):
Boolean; overload;
9、其他函数
1>、VarClear()过程清除Variant变量并将VType域的值设为varEmpty.
2>、VarCopy()将Source复制到Dest。
3>、VarCast()将一个Variant转换成指定的类型并存储在另一个Variant变量中。
4>、VarType()返回指定Variant的varXXX类型代码。
5>、VarAsType()跟VarCast()的功能一样。
6>、VarIsEmpty()如果一个Variant变量的类型代码是varEmpty则返回True。
7>、VarIsNull()判断Variant变量是否包含null值。
8>、VarToStr()将一个Variant变量转换成字符串表达式(如果Variant为varEmpty或varNUll则为空字符串)。
9>、VarFromDateTime()返回一个Variant变量,它存放着指定的TDateTime类型的值。
10>、VarToDateTime()返回在Variant中的TDateTime类型的值。
二、一个简单实例代码:
var
a, b: Variant;
I, J, K, M: Integer;
begin
//a是个一维Variant数组,元素类型是Variant,元素个数是3,上界是2,下界是0。
a :=
VarArrayOf([1234, 'abc
', Null]);
//b是一个16行4列的二维数组
b := VarArrayCreate[0, 3, 1,
16], varOleStr);
I := VarArrayHighBound(b, 1); // I是b的最大列号:3;
J := VarArrayLowBound(b, 1); // J是b的最小列号:0;
K := VarArrayHighBound(b, 2); //
K是b的最大行号:16;
M := VarArrayLowBound(b, 2); // M是b的最小行号:1。
end;
注意,Variant数组下标是列在前,行在后,元素类型是PWideChar,最大列号是3,最小列号是0,最大行号是16,最小行号是1。
三、变体类型和流的相互转换
//1、
变体类型转成流
procedure VariantToStream(const Data: OleVariant; Stream:
TStream);
var
p: Pointer;
begin
p := VarArrayLock(Data); //
加锁,并返回一个指针指向的数据。 避免运行时时刻检查
try
Stream.Write(p^, VarArrayHighBound(Data,1) + 1);
// 返回最大的列号
finally
VarArrayUnlock(Data); // 解锁,使数组能重新移动或改变大小。
end;
end;
//
2、流转成变体类型
function StreamToVariant(Stream: TStream): OleVariant;
var
p: Pointer;
begin
Result := VarArrayCreate([0, Stream.Size - 1],
varByte);// 创建一个以为的数组。类型为varByte
p := VarArrayLock(Result);
try
Stream.Position := 0; // 设置流的位置
Stream.Read(p^, Stream.Size);
finally
VarArrayUnlock(Result);
end;
end;