如何实现自定义setlength()

时间:2016-06-21 15:17:11

标签: delphi delphi-6

我想实现我自己的MySetLength()函数,该函数可能完全作为原始SetLength()(来自delphi 6)的数组,除了我想将 float 参数作为维度传递(然后,在调用原始Setlength()之前,最终将其绕入我的func中)。例如:

<label class="item item-input item-stacked-label" style="text-align:center">           
  <a class="button button-outline button-positive" href="#/app/nutrition" style="width:300px;">
     SUBMIT
  </a>
</label>

而不是原始:

procedure MySetLength(var A: Array type; Len1: **double**; Len2...);

其中A可以有任意数量的维度,可以是任何类型(字符串或浮点数)

3 个答案:

答案 0 :(得分:2)

要实现它并使其完全像SetLength那样工作,因为SetLength是一个具有编译器和运行时支持的内在函数。这是函数如何能够接受任意数组和字符串类型,并接受任意数量的维度参数。只有编译器供应商才能发挥这样的作用。

你真的没有希望产生符合问题规范的任何远程有用的东西。最好的方法是直接调用SetLength并将Round函数应用于需要舍入的任何参数。

答案 1 :(得分:2)

出现了重载和泛型:

type
  TMyHelper = class
  public
    class procedure SetLength(var A: String; Len: Double); overload; static;
    class procedure SetLength<T>(var A: TArray<T>; Len: Double); overload; static;
    class procedure SetLength<T>(var A: TArray<TArray<T>>; Len1, Len2: Double); overload; static;
    // as so on...
  end;

class procedure TMyHelper.SetLength(var A: String; Len: Double);
var
  iLen: Integer;
begin
  iLen := ...; // round Len as needed...
  System.SetLength(A, iLen);
end;

class procedure TMyHelper.SetLength<T>(var A: TArray<T>; Len: Double);
var
  iLen: Integer;
begin
  iLen := ...; // round Len as needed...
  System.SetLength(A, iLen);
end;

class procedure TMyHelper.SetLength<T>(var A: TArray<TArray<T>>; Len1, Len2: Double);
var
  iLen1, iLen2: Integer;
begin
  iLen1 := ...; // round Len1 as needed...
  iLen2 := ...; // round Len2 as needed...
  System.SetLength(A, iLen1, iLen2);
end;

// and so on...

var
  s: string;
  a1: TArray<Integer>;
  a2: TArray<TArray<String>>;
begin
  TMyHelper.SetLength(s, 10);
  TMyHelper.SetLength<Integer>(a1, 10);
  TMyHelper.SetLength<String>(a2, 5, 10);
end;

如果您使用的是不支持泛型的Delphi版本,则不能一般性地重载数组元素类型,但如果您使用的元素类型有限,您仍然可以重载数组,例如:

type
  TInteger1DimArray = array of Integer;
  TInteger2DimArray = array of TInteger1DimArray;

  TString1DimArray = array of String;
  TString2DimArray = array of TString1DimArray;

  // and so on...

  TMyHelper = class
  public
    class procedure SetLength(var A: String; Len: Double); overload; static;
    class procedure SetLength(var A: TInteger1DimArray; Len: Double); overload; static;
    class procedure SetLength(var A: TInteger2DimArray; Len1, Len2: Double); overload; static;
    class procedure SetLength(var A: TString1DimArray; Len: Double); overload; static;
    class procedure SetLength(var A: TString2DimArray; Len1, Len2: Double); overload; static;
    // as so on...
  end;

class procedure TMyHelper.SetLength(var A: String; Len: Double);
var
  iLen: Integer;
begin
  iLen := ...; // round Len as needed...
  System.SetLength(A, iLen);
end;

class procedure TMyHelper.SetLength(var A: TInteger1DimArray; Len: Double);
var
  iLen: Integer;
begin
  iLen := ...; // round Len as needed...
  System.SetLength(A, iLen);
end;

class procedure TMyHelper.SetLength(var A: TInteger2DimArray; Len1, Len2: Double);
var
  iLen1, iLen2: Integer;
begin
  iLen1 := ...; // round Len1 as needed...
  iLen2 := ...; // round Len2 as needed...
  System.SetLength(A, iLen1, iLen2);
end;

class procedure TMyHelper.SetLength(var A: TString1DimArray; Len: Double);
var
  iLen: Integer;
begin
  iLen := ...; // round Len as needed...
  System.SetLength(A, iLen);
end;

class procedure TMyHelper.SetLength(var A: TString2DimArray; Len1, Len2: Double);
var
  iLen1, iLen2: Integer;
begin
  iLen1 := ...; // round Len1 as needed...
  iLen2 := ...; // round Len2 as needed...
  System.SetLength(A, iLen1, iLen2);
end;

// and so on...

var
  s: string;
  a1: TInteger1DimArray;
  a2: TString2DimArray;
begin
  TMyHelper.SetLength(s, 10);
  TMyHelper.SetLength(a1, 10);
  TMyHelper.SetLength(a2, 5, 10);
end;

正如您所看到的,为单个SetLength()实现String很容易,但对数组实现SetLength()会变得非常复杂,具体取决于您使用的数组类型。此解决方案尽可能接近用户代码而无需借助RTTI,因此您可以直接调用RTL的DynArraySetLength()函数。

答案 2 :(得分:2)

为什么试图解决重载或替换内在问题的问题复杂化?

为什么不实施您在替换 SetLength 中使用的舍入策略,并在适当的时候将其合并到您对内在函数的调用中?

SetLength(arr, ArrayDim(dbl));

当然,您保留了 SetLength 的所有功能,包括能够在必要时将双值的维度边界规则应用于多个维度:

SetLength(multiDimArr, ArrayDim(dblDim1), ArrayDim(dblDim2));

其中 ArrayDim (或者你认为合适的名称)是一个实现舍入策略并返回指定输入的相应数组维度(整数)的函数(<强>双)。

为什么要这样做而不是简单地使用 Round()

答案是Delphi中的 Round()使用一种称为 Bankers Rounding 的特定舍入策略。这意味着 n.5 可以向上向下,具体取决于 n 的值。

即使此舍入策略适合您当前的需求,您也应该实现一个函数,以明确应用适用于数组维度的特定舍入策略,并在 SetLength()调用中使用该策略。

这不仅确保您在每种情况下都应用正确的舍入策略,还意味着如果您需要或决定更改阵列维度的舍入策略,则只需更改功能 ,而不是使用该函数调用 SetLength()