【问题标题】:About Delphi / Generic / array's : why this doesn't compile?关于 Delphi / Generic / array's:为什么这不能编译?
【发布时间】:2021-01-08 14:02:34
【问题描述】:

我想知道下面的通用代码有什么问题(用 Delphi 10.4.1 编写)。 此外,还有其他方法可以实现相同的目标吗?我的意思是在数组中搜索 (我知道我应该使用集合)。提前致谢!

问候

type
TDelphiExtention = class
public
  class function inside<T>(const value : T; const arr : array of T) : boolean;
end;

class function TDelphiExtention.inside<T>(const value : T; const arr : array of T) : boolean;
var
  i : integer;

begin
  result := true;
  for i := Low(arr) to High(arr) do begin
    if (arr[i] = value) then begin // E2015 Operator not applicable to this operand type !!!
      exit;
    end;
  end;

  result := false; // Not found
end;

// This one compiles like a charm... But is not generic :(
function inside(const value : integer; const arr : array of integer) : boolean;
var
  i : integer;

begin
  result := true;
  for i := Low(arr) to High(arr) do begin
    if (arr[i] = value) then begin
      exit;
    end;
  end;

  result := false; // Not found
end;

【问题讨论】:

  • 当说它不编译时很有帮助,你包括你得到的exact编译器错误消息。它使我们更容易找到问题所在的区域。请edit您的帖子这样做。谢谢。

标签: arrays delphi generics


【解决方案1】:

T 实际上可以是任何东西。编译器不知道如何比较给定任意类型的相等性。例如,假设T 是一条记录。如果您尝试编写A = B,其中AB 属于该记录类型,那也将是编译器错误。数组也是如此。

您可以使用System.Generics.Defaults 单元的功能来获得相等比较器:

class function TDelphiExtention.inside<T>(const value: T;
  const arr: array of T): boolean;
var
  i: integer;
  comparer: IEqualityComparer<T>;
begin
  comparer := TEqualityComparer<T>.Default;

  for i := Low(arr) to High(arr) do
  begin
    if comparer.Equals(arr[i], value) then
    begin
      result := true;
      exit;
    end;
  end;

  result := false; // Not found
end;

请注意,并非所有类型都有适当的相等比较器,因此您可能需要提供一个接受相等比较器作为参数的重载。

class function TDelphiExtention.inside<T>(const value: T;
  const arr: array of T; comparer: IEqualityComparer<T>): boolean;
var
  i: integer;
begin
  for i := Low(arr) to High(arr) do
  begin
    if comparer.Equals(arr[i], value) then
    begin
      result := true;
      exit;
    end;
  end;

  result := false; // Not found
end;

FWIW,您的方法最好命名为 Contains,因为这符合大多数其他 Delphi 库使用的命名约定。

【讨论】:

【解决方案2】:

好吧,我已经疯狂地挖掘了一些东西,我对我的发现有点惊讶。

  • Unit System.pas 将 TArray 定义为 T 数组的别名
  • 单元 System.Generics.Collections 定义 TArray = 类 仅包含静态类方法(已经很有趣),但很少有经典方法。 到目前为止,这里没有包含!
  • Unit Spring.Collections 定义了很多有趣的集合,但仅此而已 支持数组一。事实上 CreateArray 确实存在但已经消失了...... 而且文档经常过时:(
  • 赶紧看了一下单元Rapid.Generics,好像太打扰了,没有谓词搜索, 不符合我的要求

==> 最后我的天真方法似乎到处都不见了!-) 我的下一个问题是为什么数组被如此拒绝? 仍然需要 Single、First、Any 及其默认变体

最后但并非最不重要的一点是,建议的修复非常好,但只是“推迟”了这种情况。

IEqualityComparer = 接口 function Equals(const Left, Right: T): Boolean;

为什么 Delphi 编译器不能直接将我的 arr[i] 解释为 T 甚至值 T ?

if (value = value) then begin
   // Does not compile
end;
if (arr[i] = arr[i]) then begin
   // Idem
end;

编译器很挑剔!

问候

【讨论】:

  • 这不能回答问题
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-03-01
  • 2014-10-09
  • 2012-07-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多