在不复制的情况下引用 Delphi 变体数组
Reference a Delphi variant array without copying
这似乎是一个奇怪的请求,但有一个很好的理由(代码生成应用程序)。我将变体数组传递给包含在变体数组中的过程,如下所示:
TVarArray = array of variant;
procedure TMainForm.Button1Click(Sender: TObject);
var
params: TVarArray;
numRows: integer;
numCols: integer;
i: integer;
j: integer;
begin
SetLength(params, 2);
numRows := 2;
numCols := 2;
params[0] := 5;
params[1] := VarArrayCreate([1, numRows, 1, numCols], varVariant);
for i := 1 to numRows do
for j := 1 to numCols do
params[1][i, j] := i + j;
TestProc(params);
end;
procedure TMainForm.TestProc(params: TVarArray);
var
arr: variant;
p: PVariant;
v: variant;
begin
arr := params[1]; // -- Copies the array to arr.
arr[2, 2] := 99;
p := @(params[1]);
p^[2, 2] := 88; // -- Directly reference the passed-in array.
v := p^; // -- Copies the array to v -> How to prevent?
v[2, 2] := 77; // -- This should change the value in the original array.
edit1.Text := VarToStr(arr[2, 2]); // -- 99
edit2.Text := VarToStr(params[1][2, 2]); // -- 88 - should be 77
edit3.Text := VarToStr(v[2, 2]); // -- 77
end;
我不想创建数组的副本,所以可以使用 p^[] 直接访问传入的数组。但是,我不想在 TestProc 中使用 p^ 语法,而是更愿意使用不带 ^ 的变量名。当然,如果我尝试 v := p^ 我只会得到一份副本。有没有办法解决?谢谢!
您正在寻找的是一个局部变量,它可以作为 reference 其他东西(特别是 Variant
数组中的一个元素) .但是,Delphi 没有提供创建 "local reference" 变量的方法。引用仅存在于作为 var
、out
或有时 const
.
传递的参数的上下文中
或许您可以引入一个子程序并将 param[1]
作为 var
参数传递。在子例程中,您可以引用该参数,它会将数组元素作为调用者的别名。例如:
procedure ModifyVariant(var p: Variant);
begin
p[2, 2] := 77;
end;
procedure TMainForm.TestProc(params: TVarArray);
var
p: PVariant;
begin
p := @params[1];
ModifyVariant(params[1]);
Assert(params[1][2, 2] = p^[2, 2]);
end;
ModifyVariant
甚至可以是匿名过程,因此您可以在与调用者相同的范围内实现:
procedure TMainForm.TestProc(params: TVarArray);
var
ModifyVariant: reference to procedure(var x: Variant);
p: PVariant;
begin
p := @params[1];
ModifyVariant := procedure(var v: Variant)
begin
v[2, 2] := 77;
end;
ModifyVariant(params[1]);
Assert(params[1][2, 2] = p^[2, 2]);
end;
不过,这些看起来都不是特别吸引人,特别是如果您担心仅指针访问会 "spook" 您的代码的使用者。
您提到过您希望用户将他们自己的代码合并到您生成的代码中。我不建议那样做。毕竟,在他们重新 运行 您的代码生成器之后,他们期望做什么?他们肯定会失去他们所做的任何定制。最好将生成的代码分开,最好放在单独的文件中。对于用户自定义,你可以以用户可以实现的回调函数的形式提供钩子。这样,例如,用户可以提供类似于 ModifyVariant
的内容,然后您生成的代码就可以简单地调用它。您将拥有 "Variant references," 并且生成的代码与用户代码完全分开。
这似乎是一个奇怪的请求,但有一个很好的理由(代码生成应用程序)。我将变体数组传递给包含在变体数组中的过程,如下所示:
TVarArray = array of variant;
procedure TMainForm.Button1Click(Sender: TObject);
var
params: TVarArray;
numRows: integer;
numCols: integer;
i: integer;
j: integer;
begin
SetLength(params, 2);
numRows := 2;
numCols := 2;
params[0] := 5;
params[1] := VarArrayCreate([1, numRows, 1, numCols], varVariant);
for i := 1 to numRows do
for j := 1 to numCols do
params[1][i, j] := i + j;
TestProc(params);
end;
procedure TMainForm.TestProc(params: TVarArray);
var
arr: variant;
p: PVariant;
v: variant;
begin
arr := params[1]; // -- Copies the array to arr.
arr[2, 2] := 99;
p := @(params[1]);
p^[2, 2] := 88; // -- Directly reference the passed-in array.
v := p^; // -- Copies the array to v -> How to prevent?
v[2, 2] := 77; // -- This should change the value in the original array.
edit1.Text := VarToStr(arr[2, 2]); // -- 99
edit2.Text := VarToStr(params[1][2, 2]); // -- 88 - should be 77
edit3.Text := VarToStr(v[2, 2]); // -- 77
end;
我不想创建数组的副本,所以可以使用 p^[] 直接访问传入的数组。但是,我不想在 TestProc 中使用 p^ 语法,而是更愿意使用不带 ^ 的变量名。当然,如果我尝试 v := p^ 我只会得到一份副本。有没有办法解决?谢谢!
您正在寻找的是一个局部变量,它可以作为 reference 其他东西(特别是 Variant
数组中的一个元素) .但是,Delphi 没有提供创建 "local reference" 变量的方法。引用仅存在于作为 var
、out
或有时 const
.
或许您可以引入一个子程序并将 param[1]
作为 var
参数传递。在子例程中,您可以引用该参数,它会将数组元素作为调用者的别名。例如:
procedure ModifyVariant(var p: Variant);
begin
p[2, 2] := 77;
end;
procedure TMainForm.TestProc(params: TVarArray);
var
p: PVariant;
begin
p := @params[1];
ModifyVariant(params[1]);
Assert(params[1][2, 2] = p^[2, 2]);
end;
ModifyVariant
甚至可以是匿名过程,因此您可以在与调用者相同的范围内实现:
procedure TMainForm.TestProc(params: TVarArray);
var
ModifyVariant: reference to procedure(var x: Variant);
p: PVariant;
begin
p := @params[1];
ModifyVariant := procedure(var v: Variant)
begin
v[2, 2] := 77;
end;
ModifyVariant(params[1]);
Assert(params[1][2, 2] = p^[2, 2]);
end;
不过,这些看起来都不是特别吸引人,特别是如果您担心仅指针访问会 "spook" 您的代码的使用者。
您提到过您希望用户将他们自己的代码合并到您生成的代码中。我不建议那样做。毕竟,在他们重新 运行 您的代码生成器之后,他们期望做什么?他们肯定会失去他们所做的任何定制。最好将生成的代码分开,最好放在单独的文件中。对于用户自定义,你可以以用户可以实现的回调函数的形式提供钩子。这样,例如,用户可以提供类似于 ModifyVariant
的内容,然后您生成的代码就可以简单地调用它。您将拥有 "Variant references," 并且生成的代码与用户代码完全分开。