如何使用重载运算符将空集分配给记录
How to assign an empty set to a record using overloaded operators
我正在使用一条记录来封装两个不同的集合。
我已经放入运算符以允许将任一集合分配给记录。这样做会清除另一组。
但是我不能分配一个空集。
参见下面的示例代码:
Program test;
{$Apptype console}
type
TSomeThing = (a,b,c);
TOtherThing = (x,y,z);
TSomeThings = set of TSomething;
TOtherThings = set of TOtherThing;
TSomeRecord = record
strict private
Fa: TSomeThings;
Fb: TOtherThings;
public
class operator Implicit(a: TSomeThings): TSomeRecord;
class operator Implicit(a: TOtherThings): TSomeRecord;
end;
implementation
class operator TSomeRecord.Implicit(a: TSomeThings): TSomeRecord;
begin
Result.Fa:= a;
Result.Fb:= [];
end;
class operator TSomeRecord.Implicit(a: TOtherThings): TSomeRecord;
begin
Result.Fa:= [];
Result.Fb:= a;
end;
var
SomeRec: TSomeRecord;
begin
SomeRec:= [];
end.
[dcc64 Error] InstructionList.pas(512): E2010 Incompatible types: 'TSomeRecord' and 'Set'
如何才能将空集分配给我的记录?
我可以滥用隐式运算符来允许 SomeRec:= nil;
,但这看起来很丑陋。
编译器无法判断您指的是 TSomeThing
的空集还是 TOtherThing
的空集。您可以声明类型化常量以允许编译器解析重载:
const
EmptySomeThings: TSomeThings = [];
EmptyOtherThings: TOtherThings = [];
然后以下赋值将按您预期的方式编译和解析:
SomeRec:= EmptySomeThings;
SomeRec:= EmptyOtherThings;
当然,您知道其中任何一个都具有相同的效果,因为 Implicit
运算符的实现设置了一个字段,并清除了另一个字段。但是编译器无法知道这一点。
如果您想清除记录中的两个成员,您可以随时使用:
SomeRec:= Default(TSomeRecord);
我个人可能会将其包装在静态 class 方法中,如下所示:
class function Default: TSomeRecord; static;
....
class function TSomeRecord.Default: TSomeRecord;
begin
Result := Default(TSomeRecord);
end;
那你可以这样写:
SomeRec:= TSomeRecord.Default;
在理想情况下,您可以在类型中声明常量,但语言设计者没有想到这一点,遗憾的是这是不可能的。
更新
Rudy 在评论中正确指出,可以通过记录助手将常量添加到记录类型。这对我来说是个新闻,因为我错误地认为助手只能添加方法。这就是我喜欢 Stack Overflow 的地方。即使您认为自己非常了解某事,也总是有获得更多知识的余地。谢谢鲁迪。
所以你可以这样写:
type
TSomeRecordHelper = record helper for TSomeRecord
public
const
Default: TSomeRecord = ();
end;
我正在使用一条记录来封装两个不同的集合。
我已经放入运算符以允许将任一集合分配给记录。这样做会清除另一组。
但是我不能分配一个空集。
参见下面的示例代码:
Program test;
{$Apptype console}
type
TSomeThing = (a,b,c);
TOtherThing = (x,y,z);
TSomeThings = set of TSomething;
TOtherThings = set of TOtherThing;
TSomeRecord = record
strict private
Fa: TSomeThings;
Fb: TOtherThings;
public
class operator Implicit(a: TSomeThings): TSomeRecord;
class operator Implicit(a: TOtherThings): TSomeRecord;
end;
implementation
class operator TSomeRecord.Implicit(a: TSomeThings): TSomeRecord;
begin
Result.Fa:= a;
Result.Fb:= [];
end;
class operator TSomeRecord.Implicit(a: TOtherThings): TSomeRecord;
begin
Result.Fa:= [];
Result.Fb:= a;
end;
var
SomeRec: TSomeRecord;
begin
SomeRec:= [];
end.
[dcc64 Error] InstructionList.pas(512): E2010 Incompatible types: 'TSomeRecord' and 'Set'
如何才能将空集分配给我的记录?
我可以滥用隐式运算符来允许 SomeRec:= nil;
,但这看起来很丑陋。
编译器无法判断您指的是 TSomeThing
的空集还是 TOtherThing
的空集。您可以声明类型化常量以允许编译器解析重载:
const
EmptySomeThings: TSomeThings = [];
EmptyOtherThings: TOtherThings = [];
然后以下赋值将按您预期的方式编译和解析:
SomeRec:= EmptySomeThings;
SomeRec:= EmptyOtherThings;
当然,您知道其中任何一个都具有相同的效果,因为 Implicit
运算符的实现设置了一个字段,并清除了另一个字段。但是编译器无法知道这一点。
如果您想清除记录中的两个成员,您可以随时使用:
SomeRec:= Default(TSomeRecord);
我个人可能会将其包装在静态 class 方法中,如下所示:
class function Default: TSomeRecord; static;
....
class function TSomeRecord.Default: TSomeRecord;
begin
Result := Default(TSomeRecord);
end;
那你可以这样写:
SomeRec:= TSomeRecord.Default;
在理想情况下,您可以在类型中声明常量,但语言设计者没有想到这一点,遗憾的是这是不可能的。
更新
Rudy 在评论中正确指出,可以通过记录助手将常量添加到记录类型。这对我来说是个新闻,因为我错误地认为助手只能添加方法。这就是我喜欢 Stack Overflow 的地方。即使您认为自己非常了解某事,也总是有获得更多知识的余地。谢谢鲁迪。
所以你可以这样写:
type
TSomeRecordHelper = record helper for TSomeRecord
public
const
Default: TSomeRecord = ();
end;