delphi – 为什么两个别名对“数组的字符串”进行不同的对待?

前端之家收集整理的这篇文章主要介绍了delphi – 为什么两个别名对“数组的字符串”进行不同的对待?前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
在Pascal中有两种类型的声明:

>键入别名:type NewName = OldType
> type creation: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.

根据我的理解,这些是帕斯卡基础知识.

现在我们来看一下某个类型和两个别名:

> 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;

没有解释…

PPS.现在有很多doc参考.我想强调一点:虽然这个限制可能间接地继承自1949年的帕斯卡报告,但今天是2012年,德尔福与半个世纪前的实验室有很大的不同.
我命名几个BAD效果来保持这种限制,但没有看到任何好的.

讽刺的是,这种限制可以在不违反Pascal规则的情况下得到解决:在Pascal中,没有开放阵列和动态数组这样的非严格的野兽.所以让这些原始的固定数组按照自己的意愿进行限制,但是开放数组和动态数组并不是Pascal的公民,也没有必要被它的码本所限制!

请告诉Emba在QC或甚至在这里,但如果你只是通过没有表达你的意见 – 没有什么会改变!

解决方法

理解这个问题的关键是语言指南中的 Type Compatibility and Identity主题.我建议你很好的阅读这个话题.

简化示例也是有帮助的.在例子中列入仿制药主要是使事情复杂化和混淆.

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.

从文档:

When one type identifier is declared using another type identifier,without qualification,they denote the same type.

这意味着TInteger1和TInteger2是相同的类型,并且确实与Integer类型相同.

在文档中有一点是这样的:

Language constructions that function as type names denote a different type each time they occur.

TArray1和TArray2的声明属于这一类别.这意味着这两个标识符表示不同的类型.

现在我们来看一下讨论兼容性的部分.这给出了一组遵循的规则来确定两种类型是兼容还是兼容兼容.我们实际上可以通过参考另一个帮助主题Structured Types,Array Types and Assignments其中明确指出的讨论:

Arrays are assignment-compatible only if they are of the same type.

这使得清楚为什么分配Array1:= Array2导致编译器错误.

你的代码查看传递的参数,但我的重点是分配.问题是一样的,因为Calling Procedures and Functions的帮助主题解释:

When calling a routine,remember that:

  • expressions used to pass typed const and value parameters must be assignment-compatible with the corresponding formal parameters.
  • …….

猜你在找的Delphi相关文章