我可以声明以下重载来扩展集合的限制。
TMyInteger = record
private
Data: integer;
public
class operator In(a: TMyInteger; b: array of integer): boolean;
end;
class operator TMyInteger.In(a: TMyInteger; b: array of integer): boolean;
begin
Result:= false;
for i in b do
if a.data = i then exit(true);
end;
这允许使用以下语法:
if a in [500,600] then ....
有没有办法允许以下语法?
if a in [500..600] then ....
//or some similar construct?
简短的回答是否定的,但你可以实现类似的东西,就像这样。它处理格式('5, 17-30, 69')等范围。请注意,我使用"-"而不是".."
请注意,我刚刚剪切和粘贴了我使用多年的函数 - 对于这个特定目的,您可能会做得更好。
unit UnitTest2;
interface
uses
System.SysUtils;
type
TMyInteger = record
private
Data: integer;
public
class operator In(a: TMyInteger; const pVal : string): boolean;
end;
implementation
{ TMyInteger }
type EDSMListError = class(Exception);
function SplitDSMList( var List : string;
var First : integer;
var Last : integer ) : boolean;
var
i : integer;
ProcessingLast : boolean;
begin
// splits list of form like '1-3,5,9,11-23' and so on
// Returns TRUE if there has been a split, and false otherwise.
// Space characters are ignored
// If the above string were passed, the return values would be
// List = '5,9,11-23'
// First = 1
// Last = 3
// return = TRUE
// The next call would return
// List = '9,11-23'
// First = 5
// Last = 5
Result := FALSE;
First := 0;
Last := 0;
ProcessingLast := FALSE;
for i := 1 to Length( List ) do
begin
case List[i] of
'0'..'9':
begin
if ProcessingLast then
begin
Last := Last * 10 + Ord(List[i]) - Ord('0');
Result := TRUE;
end
else
begin
First := First * 10 + Ord(List[i]) - Ord('0');
Last := First;
Result := TRUE;
end;
end;
'-':
begin
ProcessingLast := TRUE;
Last := 0;
Result := TRUE;
end;
',':
begin
Result := TRUE;
List := Copy( List, i + 1, Length( List ) - i);
Exit;
end;
' ':
// ignore spaces
;
else
// illegal character
raise EDSMListError.Create('Illegal character found in list "' + List + '"');
end;
end;
// If we get here we have reached the end of the message, so...
List := '';
end;
function ValueInDSMList( const List : string; const Val : integer ) : boolean;
var
iList : string;
iBegin, iEnd : integer;
begin
iList := List;
Result := FALSE;
while SplitDSMList( iList, iBegin, iEnd ) do
begin
// assume sorted!
if Val < iBegin then
begin
exit;
end
else if Val <= iEnd then
begin
Result := TRUE;
exit;
end;
end;
end;
class operator TMyInteger.In(a: TMyInteger; const pVal: string): boolean;
begin
Result := ValueInDSMList( pVal, a.Data );
end;
end.
然后你会使用类似的东西
如果 a 在"500-600"中,那么....
根据大卫的评论:像if a in [500..600]
这样的结构是不可能的。
从性能的角度来看(至少 32 位),最好的替代解决方法是:
这也给出了一个非常干净和灵活的语法。
case a of
500..600: ;//do work
end;
//or:
if InRange(a, 500,600) then
在 64 位中,复杂的 case 语句不会得到优化,因此不要在紧密循环中使用它。
在 x64 中,case
需要 1 个 CPU 周期,InRange
需要 4 个 CPU 周期1。
因此,性能差异可以忽略不计。
1 使用RDTSCP
来测量时序;单个周期是由于无序优化。