Delphi / 通用 / 数组:为什么这段代码无法编译?

3
我想知道以下通用代码(使用 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;

当你说代码“无法编译”时,如果能够提供确切的编译器错误信息,那将非常有帮助。这样我们就可以更容易地定位问题所在的区域。请编辑你的帖子并提供相关信息。谢谢。 - Ken White
2个回答

5

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;

就我所知,您的方法最好被命名为Contains,因为这与大多数其他Delphi库使用的命名约定相符。


1
可能也值得推荐一下Spring4d库,它具有这种功能(以及更多)。 - David Heffernan
确实,我的错!好观点 :p http://docs.spring4d.org/index.htm?Spring.TArray.Contains(T).htm - mderie

-2
嗯,我做了一些调查,对我的发现感到有些惊讶。
  • 单元System.pasTArray<T>定义为array of T的别名
  • 单元System.Generics.Collections定义了TArray = class,只包含静态类方法(已经很有趣了),但经典方法非常少。 这里迄今为止还没有contains!
  • 单元Spring.Collections定义了许多有趣的集合,但不再支持数组。实际上,CreateArray确实存在,但已经消失了... 而且文档经常过时:(
  • 快速查看了单元Rapid.Generics,它似乎太过侵入式,没有谓词搜索,不符合我的要求

==> 最后,我的天真方法似乎无处可寻!-) 我的下一个问题是,为什么数组如此被拒绝? 仍然需要SingleFirstAny及其默认变体

最后但并非最不重要的是,提出的修复方案很好,但只是“推迟”了情况。

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;

编译器真挑剔!

这并没有回答问题。 - David Heffernan

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接