如何创建一个接受可变数量的变量参数的函数?

时间:2012-11-07 12:45:37

标签: delphi

可以创建一个接受可变数量参数的函数:

function f(const x: array of const): String;

并以这种方式使用它:

f([1,3,4, "hello"]);

也可以将参数定义为“可更改”:

function g(var x: Byte): String;

var B: Byte;
g(B);

但是有可能定义一个函数,它可以接受任何类型的任何参数并改变它们的所有值吗? 我知道我可以使用指针执行此操作,但后来我不知道传递的参数的类型,因此弄乱它们是非常不安全的。


我只想创建一个函数,它可以返回许多不同类型的可变数量的变量,而不仅仅是1种类型或只有1个变量。而且我不想编写数以万计的行来使用函数 - 它应该只是函数本身,在函数调用之前没有SetLength()或任何东西。所以这是迄今为止我做的最好的事情:

type TVarArr = Array of Variant;
     PVarArr = ^TVarArr;
Procedure f(a: PVarArr);
var
 i:Integer;
begin
  SetLength(A^, 4);
  a^[0] := 46;
end;

ar: TVarArr;
begin
f(@ar);
caption := IntToStr(ar[0]);

2 个答案:

答案 0 :(得分:2)

汤姆将无法使用这个答案,因为他的德尔福版本不够高,但D2010或更高版本的任何人都可以将扩展的rtti的TValue用于此类挑战。

以下是一个小型控制台应用,展示了如何:

  • 从开放数组参数创建一个动态的TValue数组;
  • 将TValue的动态数组复制到新的动态数组中,在路上修改单个值;
  • 修改“就地”动态数组中的项目。

享受。

program Project1;

{$APPTYPE CONSOLE}

{$R *.res}

uses
  System.Rtti,
  System.SysUtils,
  System.TypInfo;

const
  StringKinds: set of TTypeKind = [tkChar, tkString, tkWChar, tkLString, tkWString, tkUString];

type
  TValueArray = array of TValue;

function ValueArrayFromConstArray(const aSource: array of TValue): TValueArray;
var
  idx: Integer;
begin
  SetLength(Result, Length(aSource));
  for idx := Low(aSource) to High(aSource) do
    Result[idx] := aSource[idx];
end;

function ReturnNewArray(const aSource: TValueArray): TValueArray;
var
  idx: Integer;
begin
  SetLength(Result, Length(aSource));
  for idx := Low(aSource) to High(aSource) do
    if aSource[idx].Kind in StringKinds then
      Result[idx] := 'Dest' + aSource[idx].ToString
    else
      if aSource[idx].Kind in [tkInteger] then
        Result[idx] := 10 + aSource[idx].AsInteger
      else
        Result[idx] := aSource[idx];
end;

procedure ModifyArrayValues(var aArray: TValueArray);
var
  idx: Integer;
begin
  for idx := Low(aArray) to High(aArray) do
    if aArray[idx].Kind in StringKinds then
      aArray[idx] := 'Dest' + aArray[idx].ToString
    else
      if aArray[idx].Kind in [tkInteger] then
        aArray[idx] := 10 + aArray[idx].AsInteger
      else
        ;//aArray[idx] := aArray[idx];
end;

var
  Source: TValueArray;
  Destination: TValueArray;
  Item: TValue;
  idx: Integer;
begin
  Source := ValueArrayFromConstArray(['Some', 42, TObject]);
  Destination := ReturnNewArray(Source);
  idx := 0;
  WriteLn('', #9, 'Old', #9, 'New');
  WriteLn('-', #9, '----', #9, '----');
  for Item in Source do
  begin
    WriteLn(idx, #9, Item.ToString, #9, Destination[idx].ToString);
    Inc(idx);
  end;
  WriteLn;
  WriteLn;
  WriteLn('', #9, 'Modified');
  WriteLn('-', #9, '----');
  Source := ValueArrayFromConstArray(['first', 50, TValue.From<TFloatValue>(fvCurrency)]);
  ModifyArrayValues(Source);
  for Item in Source do
  begin
    WriteLn(idx, #9, Item.ToString);
  end;
  ReadLn;
end.

答案 1 :(得分:1)

Procedure All(var a:Array of Variant);
var
 i:Integer;
begin
  for I := Low(a) to High(a) do
      begin

        if VarType(a[i])=258  then
          a[i] := a[i] + ' modified';

      end;
end;

Procedure AllConst( a:Array of Variant);
var
 i:Integer;
begin
  for I := Low(a) to High(a) do
      begin
        Showmessage(a[i]);
      end;
end;


procedure TForm3.Button1Click(Sender: TObject);
var
 a:Array of Variant;
begin
  AllConst([1,2,'Test']);
  SetLength(a,3);
  a[0] := 3.141;
  a[1] := 'Test';
  a[2] := 27;
  all(a);
  Showmessage(a[1]);
end;