在 Pascal 中有两种类型声明:
- 类型别名:type NewName = OldType
- 类型创建:type NewType = type OldType
前者只是创建方便的简写,就像C 中的typedef一样。别名彼此兼容,并且与它们的原始类型兼容。创建的类型是故意不兼容的,如果没有明确的和不安全的定义类型转换,就不能混合。
var
nn: NewName; nt: NewType; ot: OldType;
...
nn := ot; // should work
nt := ot; // should break with type safety violation error.
nt := NewType(ot); // Disabling type safety. Should work even if
// it has no sense semantically and types really ARE incompatible.
据我了解,这些是 Pascal 基础知识。
现在让我们看看一种特定类型及其两个别名:
- System.Types.TStringDynArray =字符串数组;
- System.TArray<T> = T的数组;
- 特别是这意味着TArray<string> =字符串数组;根据定义。
现在让我们使用返回前一个类型别名的函数并将其结果提供给期望后一个类型的函数:
uses Classes, IOUtils;
TStringList.Create.AddStrings(
TDirectory.GetFiles('c:\', '*.dll') );
TStringList.Create.AddStrings(
TArray<string>( // this is required by compiler - but why ???
TDirectory.GetFiles('c:\', '*.dll') ) );
由于类型冲突,第一个片段无法编译。第二个可以愉快地编译和工作,但是对于未来的类型更改很脆弱并且是多余的。
QC 告诉编译器是正确的,而 RTL 设计是错误的。 http://qc.embarcadero.com/wc/qcmain.aspx?d=106246
为什么编译器就在这里?为什么这些别名不兼容?甚至 RTL 的设计方式也表明它们被认为是兼容的!
PS。大卫提出了更简单的例子,不使用 TArray<T>
type T1 = array of string; T2 = array of string;
procedure TForm1.FormCreate(Sender: TObject);
function Generator: T1;
begin Result := T1.Create('xxx', 'yyy', 'zzz'); end;
procedure Consumer (const data: T2);
begin
with TStringList.Create do
try
AddStrings(data);
Self.Caption := CommaText;
finally
Free;
end;
end;
begin
Consumer(Generator);
end;
相同的陷阱没有解释......
聚苯乙烯。现在有许多文档参考。我想强调一件事:虽然这个限制可能间接继承自 1949 年的帕斯卡报告,但今天是 2012 年,德尔福使用的方式与半个世纪前的学校实验室截然不同。我列举了一些保持这种限制的坏影响,但没有看到任何好的影响。
具有讽刺意味的是,这种限制可以在不违反 Pascal 规则的情况下解除:在 Pascal 中没有像开放数组和动态数组这样的非严格野兽。所以让那些原来的固定数组随心所欲地被限制,但是开放数组和动态数组不是帕斯卡公民,没有义务被它的码本限制!
请在 QC 或什至在这里与 Emba 交流,但如果你只是路过而不表达你的意见 - 什么都不会改变!