使用 TArray<T> 而不是 Array of T 的原因是啥?

Posted

技术标签:

【中文标题】使用 TArray<T> 而不是 Array of T 的原因是啥?【英文标题】:What are the reasons to use TArray<T> instead of Array of T?使用 TArray<T> 而不是 Array of T 的原因是什么? 【发布时间】:2013-01-01 05:29:42 【问题描述】:

我正在将旧版 Delphi 应用程序迁移到 Delphi-XE2,我想知道是否有充分的理由将定义为 Array of MyType 的数组替换为 TArray&lt;MyType&gt;。那么问题是TArray&lt;T&gt; 使用而不是 Array of MyType 的优缺点是什么?

【问题讨论】:

【参考方案1】:

主要优点是不那么繁琐的类型标识规则。考虑:

a: array of Integer;
b: array of Integer;

这两个变量不兼容赋值。编写是编译器错误:

a := b;

另一方面,如果您使用通用语法:

a: TArray<Integer>;
b: TArray<Integer>;

那么这两个变量是赋值兼容的。

当然,你可以写

type
  TIntegerArray = array of Integer;

但各方需要就同一类型达成一致。如果所有代码都在您的控制之下,这很好,但是当使用来自各种来源的代码时,通用动态数组的出现会产生巨大的影响。

另一个类似的优点是你可以很容易地使用泛型数组类型作为泛型方法的返回类型。

如果没有泛型数组,您将不得不声明这种形式的类型:

TArrayOfT = array of T

在您的通用类中,这相当混乱。而且,如果您在非泛型类中编写泛型方法,那么您将无法进行该声明。泛型数组再次解决了这个问题。

TMyClass = class
  class function Foo<T>: TArray<T>; static;
end;

这一切都遵循documentation 中描述的类型兼容性规则,如下所示:

类型兼容性

两个未实例化的泛型被认为是赋值 仅当它们相同或为别名时才兼容 普通类型。

两个实例化的泛型被认为是赋值 如果基本类型相同(或者是 common type) 和类型参数是相同的。

【讨论】:

泛型臃肿的代码怎么办?问题在 XE2/XE3 中解决了吗?我永远不会建议将变量声明为 TArray. @Serg:这还没有解决,但它不适用于这里。问题是方法被重复多次,但TArray&lt;T&gt; 不是一个类,它是一个数组。因此没有可复制的方法,因此没有代码膨胀。 我很少发现 TArray&lt;T&gt; 被使用,但这可能是因为 Delphi 开发人员仍然大多像 1996 年那样编写代码。这是一种保守的方法,至少在十年内忽略了新语法。 (笑) @Warren 我们的代码库仅出于我的回答中所述的原因使用它。在我看来,这很简单。 在方法中声明常量数组参数的一个重要方面是使用AMethod(const a : array of T); 而不是AMethod(const a : TArray&lt;T&gt;);。前者接受传递任何 T 数组,也接受像调用AMethod([1,2,3]); 这样的常量表达式,而后者只接受TArray&lt;T&gt; 类型的参数。【参考方案2】:

它对函数结果很有用。

示例:

Delphi 中不允许以下内容。您需要在这里声明一个单独的类型。真是浪费时间。

function MyFunc:array of integer; 
begin
end;

等等,resque 的泛型:

function MyFunc:TArray<integer>;
begin
end;

【讨论】:

好吧,说句公道话,TIntegerDynArray 是在什么地方引入的? D4? D6?所以你应该使用自己定义的类型。【参考方案3】:

你可以用一个构造值初始化TArray&lt;T&gt;

var
  LArray: TArray<Integer>;
begin
  LArray := TArray<Integer>.Create(1, 2, 3, 4);

对于array of Integer,您需要编写更多代码:

var
  LArray: array of Integer;
begin
  SetLength(LArray, 4);
  LArray[0] := 1;
  LArray[1] := 2;
  LArray[2] := 3;
  LArray[3] := 4;

【讨论】:

type TMyIntArr = array of integer; var LArray : TMyIntArr; LArray := TMyIntArr.Create(1,2,3,4); 工作正常。 @LURD:+1,它适用于 Delphi 2007 以及支持泛型的更高版本(以及整数以外的类型,以确保清楚)。 @EricGrange,你能举个例子吗?我在 XE3 中反汇编了通用数组创建和动态数组创建,编译器发出相同的代码。我觉得还可以。 对不起,耽搁了,我这里不经常检查答案,检查 aig 的 asm : Tarray; ain:整数数组;开始 aig:=TArray.Create(1, 2); SetLength(ain, 2); ain[0]:=1; ain[1]:=2;在第一种情况下,您会得到一个明确的数组、一个设定的长度、一个冗长的值分配和一个数组分配,在第二种情况下,您只会得到一个设定的长度和一个直接的值分配。 @Eric:通过阅读您的文章,我认为应该在这里澄清一下,在某些速度关键的情况下,使用 Create array 伪构造函数可能会降低性能。阅读了上述 cmets 后,我以为您是在说它是越野车。不过文章不错。

以上是关于使用 TArray<T> 而不是 Array of T 的原因是啥?的主要内容,如果未能解决你的问题,请参考以下文章

如何将 List<T> 初始化为给定大小(而不是容量)?

C++ 以费波纳茨数列为权重的加权均值计算方法 wMA

为啥要在 C# 中使用 Task<T> 而不是 ValueTask<T>?

对参数使用 IReadOnlyCollection<T> 而不是 IEnumerable<T> 以避免可能的多次枚举

为啥使用 string_view 而不是广义的 container_view<T>?

android mono:使用 List<T> 而不是 ArrayAdapter 来使用 Contains 方法