3

我想我对编写代码的方式的理解还是很有限的。我尝试从 SEARCH GENERIC LISTS修改解决方案,但我无法以他接受任意关键字作为搜索参数的方式更改代码

unit Unit_TsearchableTList;

interface

uses Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants,
  System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, Vcl.Buttons,
  contnrs, Generics.Collections;

type
  TSearchableObjectList<T: class> = class(TObjectList<T>)

  public type
    TPredicate = reference to function(aItem: T; asearchValue: String): boolean;
  public
    function search(aFound: TPredicate<T>; asearchValue: String): T;
  end;

implementation

function TSearchableObjectList<T>.search(aFound: TPredicate<T>;
  asearchValue: String): T;
var
  item: T;
begin
  for item in Self do
    * * * * * * * * COMPILE ERROR IS HERE * * * * * * * * * * * * * * * *
      * ! ! ! ! ! !
  if aFound(item, asearchValue) then
    Exit(item);
  Result := nil;
end;

end.

使用示例:

type
  TReplaceElementNames = class
    FindName: String;
    ReplaceName: String;
    ReplacementCondition: TReplacementCondition; // not relevant code
  end;

var
  LookUpList: TList<TReplaceElementNames>;
  search    : TReplaceElementNames;

begin
  LookUpList := TSearchableObjectList<TReplaceElementNames>.Create;

  search := LookUpList.search(
    function(aItem: TReplaceElementNames; searchname: String): boolean
    begin
      Result := aItem.FindName = searchname;
    end);
4

2 回答 2

2

您在代码中定义的类型是TPredicate. 但是您随后继续使用TPredicate<T>which 是SysUtils. 只需更换

TPredicate<T>

TPredicate

在您的代码中,它将编译。


话虽如此,如果您在接受的答案中使用代码会更简单。不需要两个参数谓词,因为变量捕获用于提供搜索字符串。

于 2013-07-19T12:08:26.527 回答
1

根据定义,谓词是一些东西,它只接受一个参数,如http://docwiki.embarcadero.com/Libraries/XE2/en/System.SysUtils.TPredicate

那么,我们如何向它传递更多参数,比如要比较什么?我们通过捕获 ocntext 并在该上下文固定的情况下生成新的临时函数来做到这一点。

修改你的例子(我尽量详细,所以你可以跟踪这些步骤):

Type CanCompareWithString<T> = function (const Value:T; const Target: string): boolean;
// overcoming Delphi limitation

Function CreatePredicateFunction<T>(Const Target: String; Const Matcher: CanCompareWithString<T>): TPredicate<T>;
begin
   Result := function // creating new function (more correct: new closure)
                (Arg1: T): Boolean // see top link to Delphi docs
                begin
                  Result := 
                     Matcher // capturing the passed function
                     ( Arg1, 
                       Target ) // capturing the target value
                end;    // finished creating closure
    end;


  TSearchableObjectList<T: class> = class(TObjectList<T>)
  public
    function search(aFound: TPredicate<T>): T; overload;
    function search( asearchValue: String; Matcher: CanCompareWithString<T>): T; overload;
  end;

function TSearchableObjectList<T>.search(aFound: TPredicate<T>): T;
var
  item: T;
begin
  for item in Self do
  if aFound(item) then
    Exit(item);
  Result := Default(T);
end;

function TSearchableObjectList<T>.search( asearchValue: String;  Matcher: CanCompareWithString<T>): T;
begin
  Result := 
    Search(
       CreatePredicateFunction(
           Matcher, aSearchValue)
    ); 
end;

你怎么能用它?希望是这样的:

function StringMatcher(const Value:string; const Target: string): boolean;
begin
   Result := Value = Target;
end;

var L_S : TSearchableObjectList<String>; S: String;

S := L_S.Search('abcde', StringMAtcher);

现在你可能会问“为什么?为什么是 StringMatcher?”

问题在于,在 Delphi 中,您不能对具有类型的运算符添加部分约束(在 Scala 中称为存在类型 AFAIR)。你只是无法编译

function Equal<T>(const value: String): boolean;
begin
  Result := T = Value;
end;

function Sum<U>(const value1, value2: U): U;
begin
  Result := value1 + value2;
end;

Delphi 现在不知道该类型 T 是什么,也无法确保它是否可以与字符串进行比较,因此它无法编译该“T = Value”。

Delphi 现在不知道 U 类型是什么,也无法确定是否可以添加它,因此它无法编译“value1 + value2”。

这是一个很大的限制——但事实就是这样。

查看以下对类型的实现:

你会看到需要哪种样板来完成类似的任务(但更简单!那里的任务只是将 T 与 T 进行比较,而不是 T 与 String 进行比较)。

于 2013-07-19T14:01:58.673 回答