在Pascal中有两种类型声明:
前者只是创建方便的速记,如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.
Run Code Online (Sandbox Code Playgroud)
根据我的理解,这些是Pascal基础知识.
现在让我们看一个特定类型和两个别名:
现在让我们把函数返回前一个类型别名并将其结果提供给期望后者的函数:
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') ) );
Run Code Online (Sandbox Code Playgroud)
由于类型违规,第一个代码段无法编译.第2个愉快地编译和工作,但是对未来的类型变化是脆弱的并且是多余的.
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;
Run Code Online (Sandbox Code Playgroud)
相同的问题没有解释......
PPS.现在有很多doc refs.我想强调一件事:虽然这种限制可能间接地继承自1949年的Pascal报告,但今天是2012年,德尔福与半个世纪前的学校实验室的使用方式截然不同.我点了几个BAD效果来保持这个限制,但没有看到任何好的.
讽刺的是,这种限制可能会在不破坏Pascal规则的情况下解除:在Pascal中没有像Open Arrays和Dynamic Arrays这样的非严格的野兽.因此,让那些原始的固定数组按照他们的意愿进行限制,但Open Arrays和Dynamic Arrays不是Pascal公民,也没有义务受其代码簿的限制!
请在QC或甚至在这里与Emba联系,但如果你只是在没有表达意见的情况下过去 - 没有什么会改变!
Dav*_*nan 11
理解此问题的关键是语言指南中的类型兼容性和标识主题.我建议你对这个话题有一个很好的解读.
简化示例也很有帮助.在示例中包含泛型主要是为了使问题复杂化和混淆.
program TypeCompatibilityAndIdentity;
{$APPTYPE CONSOLE}
type
TInteger1 = Integer;
TInteger2 = Integer;
TArray1 = array of Integer;
TArray2 = array of Integer;
TArray3 = TArray1;
var
Integer1: TInteger1;
Integer2: TInteger2;
Array1: TArray1;
Array2: TArray2;
Array3: TArray3;
begin
Integer1 := Integer2; // no error here
Array1 := Array2; // E2010 Incompatible types: 'TArray1' and 'TArray2'
Array1 := Array3; // no error here
end.
Run Code Online (Sandbox Code Playgroud)
从文档:
当使用另一个类型标识符声明一个类型标识符时,它们没有限定条件,它们表示相同的类型.
这意味着,TInteger1
和TInteger2
是同一类型,的确是同一类型Integer
.
在文档中稍微进一步说明:
用作类型名称的语言结构在每次出现时表示不同的类型.
宣言TArray1
和TArray2
属于这一类.这意味着这两个标识符表示不同的类型.
现在我们需要看一下讨论兼容性的部分.这给出了一组规则,以确定两种类型是兼容的还是赋值兼容的.事实上,我们可以通过引用另一个帮助主题来快速讨论该讨论:结构化类型,数组类型和赋值清楚地说明:
只有当数组属于同一类型时,它们才是赋值兼容的.
这清楚地说明了赋值Array1 := Array2
导致编译器错误的原因.
您的代码查看了传递参数,但我的重点是分配.问题是相同的,因为调用过程和函数帮助主题解释:
在调用例程时,请记住:
- 用于传递类型const和值参数的表达式必须与相应的形式参数分配兼容.
- .......
Delphi是一种强类型语言.这意味着相同(在这种情况下,我的意思是它们的定义看起来完全相同)类型不是赋值兼容的.
在编写时,array of <type>
您定义的是类型而不是别名.正如大卫在评论中已经说过两个相同的类型
type
T1 = array of string;
T2 = array of string;
Run Code Online (Sandbox Code Playgroud)
不兼容分配.
同样如此
type
TStringDynArray = array of string;
TArray<T> = array of string;
Run Code Online (Sandbox Code Playgroud)
通常人们会忘记相同类型的不兼容性,我的猜测是他们在介绍IOUtils时所做的.从理论上讲,TStringDynArray的定义应该已经改为TStringDynArray = TArray<string>
但我想这可能会引发其他问题(不是说泛型的错误......).
归档时间: |
|
查看次数: |
2334 次 |
最近记录: |